mirror of
https://github.com/Fission-AI/OpenSpec.git
synced 2026-10-03 22:13:19 +08:00
Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f9d39c327 | ||
|
|
c9bc915f62 | ||
|
|
e4c32dbe07 | ||
|
|
2d4c98e196 | ||
|
|
be6659cd39 | ||
|
|
4ba26902df | ||
|
|
5fd8e9d66c | ||
|
|
4108563731 | ||
|
|
fbef555041 | ||
|
|
92731e2263 | ||
|
|
c574e7992d | ||
|
|
62d4391268 | ||
|
|
4573c28048 | ||
|
|
0541f93ddd | ||
|
|
be51bcbc6a | ||
|
|
1d34e72f10 | ||
|
|
36fbc898da | ||
|
|
afb73cf9ec | ||
|
|
697738bc9b | ||
|
|
37686944a9 | ||
|
|
53081fb2a2 | ||
|
|
5e2e02c090 | ||
|
|
a3cee3c2f2 | ||
|
|
f27e5e809a | ||
|
|
6b545f6ebb | ||
|
|
661059b54f |
@@ -1,13 +0,0 @@
|
||||
---
|
||||
"@fission-ai/openspec": patch
|
||||
---
|
||||
|
||||
### Improvements
|
||||
|
||||
- **Nix flake maintenance** — Version now read dynamically from package.json, reducing manual sync issues
|
||||
- **Nix build optimization** — Source filtering excludes node_modules and artifacts, improving build times
|
||||
- **update-flake.sh script** — Detects when hash is already correct, skipping unnecessary rebuilds
|
||||
|
||||
### Other
|
||||
|
||||
- Updated Nix CI actions to latest versions (nix-installer v21, magic-nix-cache v13)
|
||||
@@ -149,3 +149,7 @@ CLAUDE.md
|
||||
# Pnpm
|
||||
.pnpm-store/
|
||||
result
|
||||
|
||||
# OpenCode
|
||||
.opencode/
|
||||
opencode.json
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
# @fission-ai/openspec
|
||||
|
||||
## 1.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#627](https://github.com/Fission-AI/OpenSpec/pull/627) [`afb73cf`](https://github.com/Fission-AI/OpenSpec/commit/afb73cf9ec59c6f8b26d0c538c0218c203ba3c56) Thanks [@TabishB](https://github.com/TabishB)! - ### Bug Fixes
|
||||
|
||||
- **OpenCode command references** — Command references in generated files now use the correct `/opsx-` hyphen format instead of `/opsx:` colon format, ensuring commands work properly in OpenCode
|
||||
|
||||
## 1.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#625](https://github.com/Fission-AI/OpenSpec/pull/625) [`53081fb`](https://github.com/Fission-AI/OpenSpec/commit/53081fb2a26ec66d2950ae0474b9a56cbc5b5a76) Thanks [@TabishB](https://github.com/TabishB)! - ### Bug Fixes
|
||||
|
||||
- **Codex global path support** — Codex adapter now resolves global paths correctly, fixing workflow file generation when run outside the project directory (#622)
|
||||
- **Archive operations on cross-device or restricted paths** — Archive now falls back to copy+remove when rename fails with EPERM or EXDEV errors, fixing failures on networked/external drives (#605)
|
||||
- **Slash command hints in workflow messages** — Workflow completion messages now display helpful slash command hints for next steps (#603)
|
||||
- **Windsurf workflow file path** — Updated Windsurf adapter to use the correct `workflows` directory instead of the legacy `commands` path (#610)
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#550](https://github.com/Fission-AI/OpenSpec/pull/550) [`86d2e04`](https://github.com/Fission-AI/OpenSpec/commit/86d2e04cae76a999dbd1b4571f52fa720036be0c) Thanks [@jerome-benoit](https://github.com/jerome-benoit)! - ### Improvements
|
||||
|
||||
- **Nix flake maintenance** — Version now read dynamically from package.json, reducing manual sync issues
|
||||
- **Nix build optimization** — Source filtering excludes node_modules and artifacts, improving build times
|
||||
- **update-flake.sh script** — Detects when hash is already correct, skipping unnecessary rebuilds
|
||||
|
||||
### Other
|
||||
|
||||
- Updated Nix CI actions to latest versions (nix-installer v21, magic-nix-cache v13)
|
||||
|
||||
## 1.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+32
@@ -767,6 +767,7 @@ openspec config <subcommand> [options]
|
||||
| `unset <key>` | Remove a key |
|
||||
| `reset` | Reset to defaults |
|
||||
| `edit` | Open in `$EDITOR` |
|
||||
| `profile [preset]` | Configure workflow profile interactively or via preset |
|
||||
|
||||
**Examples:**
|
||||
|
||||
@@ -794,6 +795,37 @@ openspec config reset --all --yes
|
||||
|
||||
# Edit config in your editor
|
||||
openspec config edit
|
||||
|
||||
# Configure profile with action-based wizard
|
||||
openspec config profile
|
||||
|
||||
# Fast preset: switch workflows to core (keeps delivery mode)
|
||||
openspec config profile core
|
||||
```
|
||||
|
||||
`openspec config profile` starts with a current-state summary, then lets you choose:
|
||||
- Change delivery + workflows
|
||||
- Change delivery only
|
||||
- Change workflows only
|
||||
- Keep current settings (exit)
|
||||
|
||||
If you keep current settings, no changes are written and no update prompt is shown.
|
||||
If there are no config changes but the current project files are out of sync with your global profile/delivery, OpenSpec will show a warning and suggest running `openspec update`.
|
||||
Pressing `Ctrl+C` also cancels the flow cleanly (no stack trace) and exits with code `130`.
|
||||
In the workflow checklist, `[x]` means the workflow is selected in global config. To apply those selections to project files, run `openspec update` (or choose `Apply changes to this project now?` when prompted inside a project).
|
||||
|
||||
**Interactive examples:**
|
||||
|
||||
```bash
|
||||
# Delivery-only update
|
||||
openspec config profile
|
||||
# choose: Change delivery only
|
||||
# choose delivery: Skills only
|
||||
|
||||
# Workflows-only update
|
||||
openspec config profile
|
||||
# choose: Change workflows only
|
||||
# toggle workflows in the checklist, then confirm
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
+3
-1
@@ -568,11 +568,13 @@ Different AI tools use slightly different command syntax. Use the format that ma
|
||||
| Claude Code | `/opsx:new`, `/opsx:apply` |
|
||||
| Cursor | `/opsx-new`, `/opsx-apply` |
|
||||
| Windsurf | `/opsx-new`, `/opsx-apply` |
|
||||
| Copilot | `/opsx-new`, `/opsx-apply` |
|
||||
| Copilot (IDE) | `/opsx-new`, `/opsx-apply` |
|
||||
| Trae | `/openspec-new-change`, `/openspec-apply-change` |
|
||||
|
||||
The functionality is identical regardless of syntax.
|
||||
|
||||
> **Note:** GitHub Copilot commands (`.github/prompts/*.prompt.md`) are only available in IDE extensions (VS Code, JetBrains, Visual Studio). GitHub Copilot CLI does not currently support custom prompt files — see [Supported Tools](supported-tools.md) for details and workarounds.
|
||||
|
||||
---
|
||||
|
||||
## Legacy Commands
|
||||
|
||||
@@ -133,6 +133,52 @@ The system MUST expire sessions after 30 minutes of inactivity.
|
||||
- **SHOULD** — recommended, but exceptions exist
|
||||
- **MAY** — optional
|
||||
|
||||
### What a Spec Is (and Is Not)
|
||||
|
||||
A spec is a **behavior contract**, not an implementation plan.
|
||||
|
||||
Good spec content:
|
||||
- Observable behavior users or downstream systems rely on
|
||||
- Inputs, outputs, and error conditions
|
||||
- External constraints (security, privacy, reliability, compatibility)
|
||||
- Scenarios that can be tested or explicitly validated
|
||||
|
||||
Avoid in specs:
|
||||
- Internal class/function names
|
||||
- Library or framework choices
|
||||
- Step-by-step implementation details
|
||||
- Detailed execution plans (those belong in `design.md` or `tasks.md`)
|
||||
|
||||
Quick test:
|
||||
- If implementation can change without changing externally visible behavior, it likely does not belong in the spec.
|
||||
|
||||
### Keep It Lightweight: Progressive Rigor
|
||||
|
||||
OpenSpec aims to avoid bureaucracy. Use the lightest level that still makes the change verifiable.
|
||||
|
||||
**Lite spec (default):**
|
||||
- Short behavior-first requirements
|
||||
- Clear scope and non-goals
|
||||
- A few concrete acceptance checks
|
||||
|
||||
**Full spec (for higher risk):**
|
||||
- Cross-team or cross-repo changes
|
||||
- API/contract changes, migrations, security/privacy concerns
|
||||
- Changes where ambiguity is likely to cause expensive rework
|
||||
|
||||
Most changes should stay in Lite mode.
|
||||
|
||||
### Human + Agent Collaboration
|
||||
|
||||
In many teams, humans explore and agents draft artifacts. The intended loop is:
|
||||
|
||||
1. Human provides intent, context, and constraints.
|
||||
2. Agent converts this into behavior-first requirements and scenarios.
|
||||
3. Agent keeps implementation detail in `design.md` and `tasks.md`, not `spec.md`.
|
||||
4. Validation confirms structure and clarity before implementation.
|
||||
|
||||
This keeps specs readable for humans and consistent for agents.
|
||||
|
||||
## Changes
|
||||
|
||||
A change is a proposed modification to your system, packaged as a folder with everything needed to understand and implement it.
|
||||
|
||||
@@ -46,7 +46,7 @@ Only OpenSpec-managed files that are being replaced:
|
||||
- Windsurf: `.windsurf/workflows/openspec-*.md`
|
||||
- Cline: `.clinerules/workflows/openspec-*.md`
|
||||
- Roo: `.roo/commands/openspec-*.md`
|
||||
- GitHub Copilot: `.github/prompts/openspec-*.prompt.md`
|
||||
- GitHub Copilot: `.github/prompts/openspec-*.prompt.md` (IDE extensions only; not supported in Copilot CLI)
|
||||
- And others (Augment, Continue, Amazon Q, etc.)
|
||||
|
||||
The migration detects whichever tools you have configured and cleans up their legacy files.
|
||||
@@ -332,14 +332,14 @@ Too bad. Phase gates don't let you go back easily.
|
||||
OPSX uses actions, not phases:
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────┐
|
||||
│ ACTIONS (not phases) │
|
||||
│ │
|
||||
┌───────────────────────────────────────────────┐
|
||||
│ ACTIONS (not phases) │
|
||||
│ │
|
||||
│ new ◄──► continue ◄──► apply ◄──► archive │
|
||||
│ │ │ │ │ │
|
||||
│ └──────────┴───────────┴───────────┘ │
|
||||
│ any order │
|
||||
└────────────────────────────────────────┘
|
||||
│ │ │ │ │ │
|
||||
│ └──────────┴───────────┴─────────────┘ │
|
||||
│ any order │
|
||||
└───────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Dependency Graph
|
||||
|
||||
+10
-4
@@ -19,22 +19,28 @@ For each tool you select, OpenSpec installs:
|
||||
| Claude Code | `.claude/skills/` | `.claude/commands/opsx/` |
|
||||
| Cline | `.cline/skills/` | `.clinerules/workflows/` |
|
||||
| CodeBuddy | `.codebuddy/skills/` | `.codebuddy/commands/opsx/` |
|
||||
| Codex | `.codex/skills/` | `.codex/prompts/` |
|
||||
| Codex | `.codex/skills/` | `~/.codex/prompts/`\* |
|
||||
| Continue | `.continue/skills/` | `.continue/prompts/` |
|
||||
| CoStrict | `.cospec/skills/` | `.cospec/openspec/commands/` |
|
||||
| Crush | `.crush/skills/` | `.crush/commands/opsx/` |
|
||||
| Cursor | `.cursor/skills/` | `.cursor/commands/` |
|
||||
| Factory Droid | `.factory/skills/` | `.factory/commands/` |
|
||||
| Gemini CLI | `.gemini/skills/` | `.gemini/commands/opsx/` |
|
||||
| GitHub Copilot | `.github/skills/` | `.github/prompts/` |
|
||||
| GitHub Copilot | `.github/skills/` | `.github/prompts/`\*\* |
|
||||
| iFlow | `.iflow/skills/` | `.iflow/commands/` |
|
||||
| Kilo Code | `.kilocode/skills/` | `.kilocode/workflows/` |
|
||||
| Kiro | `.kiro/skills/` | `.kiro/prompts/` |
|
||||
| OpenCode | `.opencode/skills/` | `.opencode/command/` |
|
||||
| Pi | `.pi/skills/` | `.pi/prompts/` |
|
||||
| Qoder | `.qoder/skills/` | `.qoder/commands/opsx/` |
|
||||
| Qwen Code | `.qwen/skills/` | `.qwen/commands/` |
|
||||
| RooCode | `.roo/skills/` | `.roo/commands/` |
|
||||
| Trae | `.trae/skills/` | `.trae/skills/` (via `/openspec-*`) |
|
||||
| Windsurf | `.windsurf/skills/` | `.windsurf/commands/opsx/` |
|
||||
| Windsurf | `.windsurf/skills/` | `.windsurf/workflows/` |
|
||||
|
||||
\* Codex commands are installed to the global home directory (`~/.codex/prompts/` or `$CODEX_HOME/prompts/`), not the project directory.
|
||||
|
||||
\*\* GitHub Copilot's `.github/prompts/*.prompt.md` files are recognized as custom slash commands in **IDE extensions only** (VS Code, JetBrains, Visual Studio). GitHub Copilot CLI does not currently support custom prompts from this directory — see [github/copilot-cli#618](https://github.com/github/copilot-cli/issues/618). If you use Copilot CLI, you may need to manually set up [custom agents](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents) in `.github/agents/` as a workaround.
|
||||
|
||||
## Non-Interactive Setup
|
||||
|
||||
@@ -51,7 +57,7 @@ openspec init --tools all
|
||||
openspec init --tools none
|
||||
```
|
||||
|
||||
**Available tool IDs:** `amazon-q`, `antigravity`, `auggie`, `claude`, `cline`, `codebuddy`, `codex`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `kilocode`, `opencode`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
|
||||
**Available tool IDs:** `amazon-q`, `antigravity`, `auggie`, `claude`, `cline`, `codebuddy`, `codex`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `kilocode`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
|
||||
|
||||
## What Gets Installed
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-21
|
||||
@@ -0,0 +1,93 @@
|
||||
## Why
|
||||
|
||||
Parallel changes often touch the same capabilities and `cli-init`/`cli-update` behavior, but today there is no machine-readable way to express sequencing, dependencies, or expected merge order.
|
||||
|
||||
This creates three recurring problems:
|
||||
|
||||
- teams cannot tell which change should land first
|
||||
- large changes are hard to split into safe mergeable slices
|
||||
- parallel work can accidentally reintroduce assumptions already removed by another change
|
||||
|
||||
We need lightweight planning metadata and CLI guidance so contributors can safely stack plans on top of each other.
|
||||
|
||||
## What Changes
|
||||
|
||||
### 1. Add lightweight stack metadata for changes
|
||||
|
||||
Extend change metadata to support sequencing and decomposition context, for example:
|
||||
|
||||
- `dependsOn`: changes that must land first
|
||||
- `provides`: capability markers exposed by this change
|
||||
- `requires`: capability markers needed by this change
|
||||
- `touches`: capability/spec areas likely affected (advisory only; warning signal, not a hard dependency)
|
||||
- `parent`: optional parent change for split work
|
||||
|
||||
Metadata is optional and backward compatible for existing changes.
|
||||
|
||||
Ordering semantics:
|
||||
|
||||
- `dependsOn` is the source of truth for execution/archive ordering
|
||||
- `provides`/`requires` are capability contracts for validation and planning visibility
|
||||
- `provides`/`requires` do not create implicit dependency edges; authors must still declare required ordering via `dependsOn`
|
||||
|
||||
### 2. Add stack-aware validation
|
||||
|
||||
Enhance change validation to detect planning issues early:
|
||||
|
||||
- missing dependencies
|
||||
- dependency cycles
|
||||
- archive ordering violations (for example, attempting to archive a change before all `dependsOn` predecessors are archived)
|
||||
- unmatched capability markers (for example, `requires` marker with no provider in active history emits non-blocking warning)
|
||||
- overlap warnings when active changes touch the same capability
|
||||
|
||||
Validation should fail only for deterministic blockers (for example cycles or missing required dependencies), and keep overlap checks as actionable warnings.
|
||||
|
||||
### 3. Add sequencing visibility commands
|
||||
|
||||
Add lightweight CLI support to inspect and execute plan order:
|
||||
|
||||
- `openspec change graph` to show dependency DAG/order
|
||||
- `openspec change graph` validates for cycles first; when cycles are present it fails with the same deterministic cycle error as stack-aware validation
|
||||
- `openspec change next` to suggest unblocked changes ready to implement/archive
|
||||
|
||||
### 4. Add split scaffolding for large changes
|
||||
|
||||
Add helper workflow to decompose large proposals into stackable slices:
|
||||
|
||||
- `openspec change split <change-id>` scaffolds child changes with `parent` + `dependsOn`
|
||||
- generates minimal proposal/tasks stubs for each child slice
|
||||
- converts the source change into a parent planning container (no duplicate child implementation tasks)
|
||||
- re-running split for an already-split source change returns a deterministic actionable error unless `--overwrite` (alias `--force`) is passed
|
||||
- `--overwrite` / `--force` fully regenerates managed child scaffold stubs and metadata links for the split, replacing prior scaffold content
|
||||
|
||||
### 5. Document stack-first workflow
|
||||
|
||||
Update docs to describe:
|
||||
|
||||
- how to model dependencies and parent/child slices
|
||||
- when to split a large change
|
||||
- how to use graph/next validation signals during parallel development
|
||||
- migration guidance for `openspec/changes/IMPLEMENTATION_ORDER.md`:
|
||||
- machine-readable change metadata becomes the normative dependency source
|
||||
- `IMPLEMENTATION_ORDER.md` remains optional narrative context during transition
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `change-stacking-workflow`: Dependency-aware sequencing and split scaffolding for change planning
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `cli-change`: Adds graph/next/split planning commands and stack-aware validation messaging
|
||||
- `change-creation`: Supports parent/dependency metadata when creating or splitting changes
|
||||
- `openspec-conventions`: Defines optional stack metadata conventions for change proposals
|
||||
|
||||
## Impact
|
||||
|
||||
- `src/core/project-config.ts` and related parsing/validation utilities for change metadata loading
|
||||
- `src/core/config-schema.ts` (or dedicated change schema) for stack metadata validation
|
||||
- `src/commands/change.ts` and/or `src/core/list.ts` for graph/next/split command behavior
|
||||
- `src/core/validation/*` for dependency cycle and overlap checks
|
||||
- `docs/cli.md`, `docs/concepts.md`, and contributor guidance for stack-aware workflows
|
||||
- tests for metadata parsing, graph ordering, next-item suggestions, and split scaffolding
|
||||
@@ -0,0 +1,15 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Stack Metadata Scaffolding
|
||||
Change creation workflows SHALL support optional dependency metadata for new or split changes.
|
||||
|
||||
#### Scenario: Create change with stack metadata
|
||||
- **WHEN** a change is created with stack metadata inputs
|
||||
- **THEN** creation SHALL persist metadata fields in change configuration
|
||||
- **AND** persisted metadata SHALL be validated against change metadata schema rules
|
||||
|
||||
#### Scenario: Split-generated child metadata
|
||||
- **WHEN** child changes are generated from a split workflow
|
||||
- **THEN** each child SHALL include a `parent` link to the source change
|
||||
- **AND** SHALL include dependency metadata needed for deterministic sequencing
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Stack Metadata Model
|
||||
The system SHALL support optional metadata on active changes to express sequencing and decomposition relationships.
|
||||
|
||||
#### Scenario: Optional stack metadata is present
|
||||
- **WHEN** a change includes stack metadata fields
|
||||
- **THEN** the system SHALL parse and expose `dependsOn`, `provides`, `requires`, `touches`, and `parent`
|
||||
- **AND** validation SHALL enforce normalized field shapes and value types (`dependsOn`/`provides`/`requires`/`touches` as string arrays, `parent` as string when present)
|
||||
|
||||
#### Scenario: Backward compatibility without stack metadata
|
||||
- **WHEN** a change does not include stack metadata
|
||||
- **THEN** existing behavior SHALL continue without migration steps
|
||||
- **AND** validation SHALL not fail solely because stack metadata is absent
|
||||
|
||||
### Requirement: Change Dependency Graph
|
||||
The system SHALL provide dependency-aware ordering for active changes.
|
||||
|
||||
#### Scenario: Build dependency order
|
||||
- **WHEN** users request stack planning output
|
||||
- **THEN** the system SHALL compute a dependency graph across active changes
|
||||
- **AND** SHALL return a deterministic topological order for unblocked changes
|
||||
|
||||
#### Scenario: Tie-breaking within the same dependency depth
|
||||
- **WHEN** multiple unblocked changes share the same topological dependency depth
|
||||
- **THEN** ordering SHALL break ties lexicographically by change ID
|
||||
- **AND** repeated runs over the same input SHALL return the same order
|
||||
|
||||
#### Scenario: Dependency cycle detection
|
||||
- **WHEN** active changes contain a dependency cycle
|
||||
- **THEN** validation SHALL fail with cycle details before archive or sequencing actions proceed
|
||||
- **AND** output SHALL include actionable guidance to break the cycle
|
||||
|
||||
### Requirement: Capability marker and overlap semantics
|
||||
The system SHALL treat capability markers as validation contracts and `touches` as advisory overlap signals.
|
||||
|
||||
#### Scenario: Required capability provided by an active change
|
||||
- **WHEN** change B declares `requires` marker `X`
|
||||
- **AND** active change A declares `provides` marker `X`
|
||||
- **THEN** validation SHALL require B to declare an explicit ordering edge in `dependsOn` to at least one active provider of `X`
|
||||
- **AND** validation SHALL fail if no explicit dependency is declared
|
||||
|
||||
#### Scenario: Requires marker without active provider
|
||||
- **WHEN** a change declares a `requires` marker
|
||||
- **AND** no active change declares the corresponding `provides` marker
|
||||
- **THEN** validation SHALL NOT infer an implicit dependency edge
|
||||
- **AND** ordering SHALL continue to be determined solely by explicit `dependsOn` relationships
|
||||
|
||||
#### Scenario: Requires marker satisfied by archived history
|
||||
- **WHEN** a change declares a `requires` marker
|
||||
- **AND** no active change provides that marker
|
||||
- **AND** at least one archived change in history provides that marker
|
||||
- **THEN** validation SHALL NOT warn solely about missing provider
|
||||
- **AND** SHALL continue to use explicit `dependsOn` for active ordering
|
||||
|
||||
#### Scenario: Requires marker missing in full history
|
||||
- **WHEN** a change declares a `requires` marker
|
||||
- **AND** no active or archived change in history provides that marker
|
||||
- **THEN** validation SHALL emit a non-blocking warning naming the change and missing marker
|
||||
- **AND** SHALL NOT infer an implicit dependency edge
|
||||
|
||||
#### Scenario: Overlap warning for shared touches
|
||||
- **WHEN** multiple active changes declare overlapping `touches` values
|
||||
- **THEN** validation SHALL emit a warning listing the overlapping changes and touched areas
|
||||
- **AND** validation SHALL NOT fail solely on overlap
|
||||
@@ -0,0 +1,27 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Stack Planning Commands
|
||||
The change CLI SHALL provide commands for dependency-aware sequencing of active changes.
|
||||
|
||||
#### Scenario: Show dependency graph
|
||||
- **WHEN** a user runs `openspec change graph`
|
||||
- **THEN** the CLI SHALL display dependency relationships for active changes
|
||||
- **AND** SHALL include a deterministic recommended order for execution
|
||||
|
||||
#### Scenario: Show next unblocked changes
|
||||
- **WHEN** a user runs `openspec change next`
|
||||
- **THEN** the CLI SHALL list changes that are not blocked by unresolved dependencies
|
||||
- **AND** SHALL use deterministic tie-breaking when multiple options are available
|
||||
|
||||
### Requirement: Split Large Change Scaffolding
|
||||
The change CLI SHALL support scaffolding child slices from an existing large change.
|
||||
|
||||
#### Scenario: Split command scaffolds child changes
|
||||
- **WHEN** a user runs `openspec change split <change-id>`
|
||||
- **THEN** the CLI SHALL create child change directories with proposal/tasks stubs
|
||||
- **AND** generated metadata SHALL include `parent` and dependency links back to the source change
|
||||
|
||||
#### Scenario: Re-running split on an already-split change
|
||||
- **WHEN** a user runs `openspec change split <change-id>` for a parent whose generated child directories already exist
|
||||
- **THEN** the CLI SHALL fail with a deterministic, actionable error
|
||||
- **AND** SHALL NOT mutate existing child change content unless an explicit overwrite mode is requested
|
||||
@@ -0,0 +1,29 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Stack-Aware Change Planning Conventions
|
||||
OpenSpec conventions SHALL define optional metadata fields for sequencing and decomposition across concurrent changes.
|
||||
|
||||
#### Scenario: Declaring change dependencies
|
||||
- **WHEN** authors need to sequence related changes
|
||||
- **THEN** conventions SHALL define how to declare dependencies and provided/required capability markers
|
||||
- **AND** validation guidance SHALL distinguish hard blockers from soft overlap warnings
|
||||
|
||||
#### Scenario: Dependency source of truth during migration
|
||||
- **WHEN** both stack metadata and `openspec/changes/IMPLEMENTATION_ORDER.md` are present
|
||||
- **THEN** conventions SHALL treat per-change stack metadata as the normative dependency source
|
||||
- **AND** `IMPLEMENTATION_ORDER.md` SHALL be treated as optional narrative guidance
|
||||
|
||||
#### Scenario: Explicit ordering remains required for capability markers
|
||||
- **WHEN** authors use `provides` and `requires` markers to describe capability contracts
|
||||
- **THEN** conventions SHALL require explicit `dependsOn` edges for ordering relationships
|
||||
- **AND** conventions SHALL prohibit treating `requires` as an implicit dependency edge
|
||||
|
||||
#### Scenario: Declaring advisory overlap via touches
|
||||
- **WHEN** a change may affect capability/spec areas shared by concurrent changes without requiring ordering
|
||||
- **THEN** conventions SHALL allow authors to declare `touches` with advisory area identifiers (for example capability IDs, spec area names, or paths)
|
||||
- **AND** tooling SHALL treat `touches` as informational only (no implicit dependency edge, non-blocking validation signal)
|
||||
|
||||
#### Scenario: Declaring parent-child split structure
|
||||
- **WHEN** a large change is decomposed into smaller slices
|
||||
- **THEN** conventions SHALL define parent-child metadata and expected ordering semantics
|
||||
- **AND** docs SHALL describe when to split versus keep a single change
|
||||
@@ -0,0 +1,39 @@
|
||||
## 1. Metadata Model
|
||||
|
||||
- [ ] 1.1 Add optional stack metadata fields (`dependsOn`, `provides`, `requires`, `touches`, `parent`) to change metadata schema
|
||||
- [ ] 1.2 Keep metadata backward compatible for existing changes without new fields
|
||||
- [ ] 1.3 Add tests for valid/invalid metadata and schema evolution behavior
|
||||
|
||||
## 2. Stack-Aware Validation
|
||||
|
||||
- [ ] 2.1 Detect dependency cycles and fail validation with deterministic errors
|
||||
- [ ] 2.2 Detect missing `dependsOn` targets (referenced change ID does not exist) and detect changes transitively blocked by unresolved/cyclic dependency paths
|
||||
- [ ] 2.3 Add overlap warnings for active changes that touch the same capability/spec areas
|
||||
- [ ] 2.4 Emit advisory warnings for unmatched `requires` markers when no provider exists in active history
|
||||
- [ ] 2.5 Add tests for cycle, missing dependency, overlap warning, and unmatched `requires` cases
|
||||
|
||||
## 3. Sequencing Commands
|
||||
|
||||
- [ ] 3.1 Add `openspec change graph` to display dependency order for active changes
|
||||
- [ ] 3.2 Add `openspec change next` to suggest unblocked changes in recommended order
|
||||
- [ ] 3.3 Add tests for topological ordering and deterministic tie-breaking (lexicographic by change ID at equal depth)
|
||||
|
||||
## 4. Split Scaffolding
|
||||
|
||||
- [ ] 4.1 Add `openspec change split <change-id>` to scaffold child slices
|
||||
- [ ] 4.2 Ensure generated children include parent/dependency metadata and stub proposal/tasks files
|
||||
- [ ] 4.3 Convert the source change into a parent planning container as part of split (no duplicate child implementation tasks)
|
||||
- [ ] 4.4 Add tests for split output structure, source-change parent conversion, and deterministic re-split error behavior when overwrite mode is not requested
|
||||
- [ ] 4.5 Implement and test explicit overwrite mode for `openspec change split` (`--overwrite` / `--force`) for controlled re-splitting
|
||||
|
||||
## 5. Documentation
|
||||
|
||||
- [ ] 5.1 Document stack metadata and sequencing workflow in `docs/concepts.md`
|
||||
- [ ] 5.2 Document new change commands and usage examples in `docs/cli.md`
|
||||
- [ ] 5.3 Add guidance for breaking large changes into independently mergeable slices
|
||||
- [ ] 5.4 Document migration guidance for `openspec/changes/IMPLEMENTATION_ORDER.md` as optional narrative, not dependency source of truth
|
||||
|
||||
## 6. Verification
|
||||
|
||||
- [ ] 6.1 Run targeted tests for change parsing, validation, and CLI commands
|
||||
- [ ] 6.2 Run full test suite (`pnpm test`) and resolve regressions
|
||||
@@ -1,60 +0,0 @@
|
||||
## 1. Project Setup and Command Registration
|
||||
|
||||
- [x] 1.1 Create directory structure: `src/core/dashboard/` with `index.ts`, `server.ts`, `data.ts`, `markdown.ts`
|
||||
- [x] 1.2 Register `openspec dashboard` command in `src/cli/index.ts` with `--port` and `--no-open` options
|
||||
- [x] 1.3 Create `DashboardCommand` class in `src/core/dashboard/index.ts` that validates openspec directory exists
|
||||
|
||||
## 2. Data Gathering Module
|
||||
|
||||
- [x] 2.1 Implement `getChangesData()` in `data.ts` that returns draft/active/completed changes with artifact existence status (proposal.md, specs/, design.md, tasks.md)
|
||||
- [x] 2.2 Implement `getSpecsData()` in `data.ts` that returns specs grouped by domain prefix with requirement counts
|
||||
- [x] 2.3 Implement `getArchiveData()` in `data.ts` that returns archived changes with parsed dates, sorted reverse chronologically
|
||||
- [x] 2.4 Implement `getSummary()` in `data.ts` that aggregates counts for dashboard summary section
|
||||
- [x] 2.5 Implement `getArtifactContent()` in `data.ts` that reads a markdown file by relative path with path traversal protection
|
||||
|
||||
## 3. Markdown Renderer
|
||||
|
||||
- [x] 3.1 Implement markdown-to-HTML converter in `markdown.ts` handling headings, paragraphs, bold, italic, and line breaks
|
||||
- [x] 3.2 Add support for fenced code blocks and inline code
|
||||
- [x] 3.3 Add support for unordered lists, ordered lists, and checkboxes
|
||||
- [x] 3.4 Add support for blockquotes, horizontal rules, and links
|
||||
|
||||
## 4. HTTP Server and API
|
||||
|
||||
- [x] 4.1 Implement HTTP server in `server.ts` using Node.js built-in `http` module
|
||||
- [x] 4.2 Add route `GET /` that serves the embedded single-page HTML dashboard
|
||||
- [x] 4.3 Add route `GET /api/summary` returning aggregated project data
|
||||
- [x] 4.4 Add route `GET /api/changes` returning changes with artifact status
|
||||
- [x] 4.5 Add route `GET /api/specs` returning specs grouped by domain
|
||||
- [x] 4.6 Add route `GET /api/archive` returning archive entries with pagination (default 50)
|
||||
- [x] 4.7 Add route `GET /api/artifact?path=<relative>` returning rendered markdown HTML with path traversal guard
|
||||
- [x] 4.8 Implement port selection with auto-increment from default 3000 to 3010
|
||||
- [x] 4.9 Implement cross-platform browser opening (open/xdg-open/start)
|
||||
- [x] 4.10 Add graceful shutdown on SIGINT/SIGTERM
|
||||
|
||||
## 5. Dashboard HTML/CSS/JS
|
||||
|
||||
- [x] 5.1 Create embedded HTML template with navigation tabs for Changes, Specs, and Archive sections
|
||||
- [x] 5.2 Implement Changes view with status grouping (draft/active/completed), artifact indicators, and progress bars
|
||||
- [x] 5.3 Implement Specs view with domain-prefix grouping and requirement count display
|
||||
- [x] 5.4 Implement Archive view with date-based listing and "load more" pagination
|
||||
- [x] 5.5 Implement artifact detail panel that fetches and displays rendered markdown on click
|
||||
- [x] 5.6 Add basic responsive CSS styling with monospace fonts matching terminal aesthetic
|
||||
|
||||
## 6. Testing
|
||||
|
||||
- [x] 6.1 Add unit tests for markdown renderer in `test/core/dashboard/markdown.test.ts`
|
||||
- [x] 6.2 Add unit tests for data gathering functions in `test/core/dashboard/data.test.ts`
|
||||
- [x] 6.3 Add unit tests for path traversal prevention in artifact endpoint
|
||||
- [x] 6.4 Add unit tests for port selection logic
|
||||
- [x] 6.5 Add unit tests for domain grouping logic
|
||||
- [x] 6.6 Add unit tests for archive date parsing
|
||||
|
||||
## 7. Polish and Integration
|
||||
|
||||
- [x] 7.1 Add CLI help text for the dashboard command
|
||||
- [x] 7.2 Add shell completion entries for dashboard command and its options
|
||||
- [x] 7.3 Handle edge cases: empty project, missing directories, unparseable specs
|
||||
- [x] 7.4 Ensure cross-platform path handling with `path.join()` throughout
|
||||
- [x] 7.5 Run linting and fix any issues (`pnpm run lint`)
|
||||
- [x] 7.6 Run full test suite (`pnpm test`)
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-21
|
||||
@@ -0,0 +1,161 @@
|
||||
## Context
|
||||
|
||||
OpenSpec today assumes project-local installation for most generated artifacts, with Codex command prompts as the main global exception. This mixed model works, but it is implicit and not user-configurable.
|
||||
|
||||
The requested change is to support user-selectable install scope (`global` or `project`) for tool skills/commands, defaulting to `global` for new configurations while preserving legacy project-local behavior until explicit migration.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- Provide a single scope preference that users can set globally and override per run
|
||||
- Default new users to `global` scope
|
||||
- Make install path resolution deterministic and explicit across tools/surfaces
|
||||
- Preserve current behavior for users with older config files that do not yet define `installScope`
|
||||
- Avoid silent partial installs; surface effective scope decisions in output
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- Implementing project-local config file support for global settings
|
||||
- Defining global install paths for tools where upstream location conventions are unknown
|
||||
- Changing workflow/profile semantics (`core`, `custom`, `delivery`) in this change
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. Scope model in global config
|
||||
|
||||
Add install scope preference to global config:
|
||||
|
||||
```ts
|
||||
type InstallScope = 'global' | 'project';
|
||||
|
||||
interface GlobalConfig {
|
||||
// existing fields...
|
||||
installScope?: InstallScope;
|
||||
}
|
||||
```
|
||||
|
||||
Defaults:
|
||||
|
||||
- New configs SHOULD write `installScope: global` explicitly.
|
||||
- Existing configs without this field continue to load safely through schema evolution and SHALL resolve effective default as `project` until users explicitly set `installScope`.
|
||||
|
||||
### 2. Explicit tool scope support metadata
|
||||
|
||||
Extend `AI_TOOLS` metadata with optional scope support declarations per surface:
|
||||
|
||||
```ts
|
||||
interface ToolInstallScopeSupport {
|
||||
skills?: InstallScope[];
|
||||
commands?: InstallScope[];
|
||||
}
|
||||
```
|
||||
|
||||
Resolution rules:
|
||||
|
||||
1. If scope support metadata is absent for a tool surface, treat it as project-only support for conservative backward compatibility.
|
||||
2. Try preferred scope.
|
||||
3. If unsupported, use alternate scope when supported.
|
||||
4. If neither is supported, fail with actionable error.
|
||||
|
||||
This enables default-global behavior while remaining safe for tools that only support project-local paths.
|
||||
|
||||
### 3. Scope-aware install target resolver
|
||||
|
||||
Introduce shared resolver utilities to compute effective target paths for:
|
||||
|
||||
- skills root directory
|
||||
- command output files
|
||||
|
||||
Resolver input:
|
||||
|
||||
- tool id
|
||||
- requested scope
|
||||
- project root
|
||||
- environment context (`CODEX_HOME`, etc.)
|
||||
|
||||
Resolver output:
|
||||
|
||||
- effective scope per surface
|
||||
- concrete target paths
|
||||
- optional fallback reasons for user-facing output
|
||||
|
||||
Platform behavior:
|
||||
|
||||
- Resolver outputs are OS-aware and normalized for the current platform.
|
||||
- Windows global targets MUST use Windows path conventions (for example `%USERPROFILE%\.codex\prompts` fallback for Codex when `CODEX_HOME` is unset), not POSIX defaults.
|
||||
|
||||
### 4. Context-aware command adapter paths
|
||||
|
||||
Update command generation contract so adapters receive install context for path resolution. This avoids hardcoded absolute/relative assumptions and centralizes scope decisions.
|
||||
|
||||
Example direction:
|
||||
|
||||
```ts
|
||||
getFilePath(commandId: string, context: InstallContext): string
|
||||
```
|
||||
|
||||
### 5. CLI behavior and UX
|
||||
|
||||
`init`:
|
||||
|
||||
- Uses configured install scope by default; if absent in a legacy config, uses migration-safe effective default (`project`).
|
||||
- Supports explicit override flag (`--scope global|project`).
|
||||
- In interactive mode, displays chosen scope and any per-tool fallback decisions before writing files.
|
||||
|
||||
`update`:
|
||||
|
||||
- Applies current scope preference (or override); if absent in a legacy config, uses migration-safe effective default (`project`).
|
||||
- Performs drift detection using effective scoped paths and last-applied scope state.
|
||||
- Reports effective scope decisions in summary output.
|
||||
|
||||
`config`:
|
||||
|
||||
- `openspec config profile` interactive flow includes install scope selection.
|
||||
- `openspec config list` shows `installScope` with source annotation (`explicit`, `new-default`, or `legacy-default`).
|
||||
|
||||
### 6. Cleanup safety during scope changes
|
||||
|
||||
When scope changes:
|
||||
|
||||
- Writes occur in the new effective targets.
|
||||
- Cleanup/removal is limited to OpenSpec-managed files for the relevant tool/workflow IDs.
|
||||
- Output explicitly states which scope locations were updated and which were cleaned.
|
||||
|
||||
### 7. Scope drift state tracking
|
||||
|
||||
Track last successful effective scope per tool/surface in project-managed state.
|
||||
|
||||
Rules:
|
||||
|
||||
1. Drift is detected when current resolved scope differs from last successful scope for a configured tool/surface.
|
||||
2. Scope support MUST be validated for all configured tools/surfaces before any write starts.
|
||||
3. Update writes to newly resolved targets first, verifies completeness, then removes managed files at previous targets.
|
||||
4. If new-target writes are partial or verification fails, command SHALL abort old-target cleanup and report actionable failure with incomplete/new and preserved/old paths.
|
||||
5. Cleanup failures do not rollback new writes; command returns actionable failure with leftover paths to resolve.
|
||||
|
||||
### 8. Coordination with command-surface capability changes
|
||||
|
||||
If `add-tool-command-surface-capabilities` lands, planning logic must evaluate scope resolution and delivery/capability behavior together (scope × delivery × command surface).
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
**Risk: Cross-project shared global state**
|
||||
Global installs are shared across projects. Updating global artifacts from one project affects all projects using that tool scope.
|
||||
→ Mitigation: make scope explicit in output; keep profile/delivery global and deterministic.
|
||||
|
||||
**Risk: Tool-specific unknown global conventions**
|
||||
Not all tools document a stable global install location.
|
||||
→ Mitigation: use explicit scope support metadata; fallback or fail instead of guessing.
|
||||
|
||||
**Risk: Adapter API churn**
|
||||
Changing adapter path contracts touches many files/tests.
|
||||
→ Mitigation: migrate in one pass with adapter contract tests and existing end-to-end generation tests.
|
||||
|
||||
## Rollout Plan
|
||||
|
||||
1. Add config schema + defaults for install scope.
|
||||
2. Add tool scope capability metadata and resolver utilities.
|
||||
3. Upgrade command adapter contract and generator path plumbing.
|
||||
4. Integrate scope-aware behavior into init/update.
|
||||
5. Add documentation and test coverage.
|
||||
@@ -0,0 +1,101 @@
|
||||
## Why
|
||||
|
||||
OpenSpec installation paths are currently inconsistent:
|
||||
|
||||
- Most skills and commands are written to project-local directories.
|
||||
- Codex commands are already global (`$CODEX_HOME/prompts` or `~/.codex/prompts`).
|
||||
- Users cannot choose a consistent install scope strategy across tools.
|
||||
|
||||
This creates friction for users who prefer user-level setup and expect tool artifacts to be managed globally by default.
|
||||
|
||||
## What Changes
|
||||
|
||||
### 1. Add install scope preference with legacy-safe defaults
|
||||
|
||||
Introduce a global install scope setting with two modes:
|
||||
|
||||
- `global` (default for newly created configs)
|
||||
- `project`
|
||||
|
||||
The setting is stored in global config and can be overridden per command run.
|
||||
For schema-evolved legacy configs where `installScope` is absent, effective default remains `project` until users opt in to global scope.
|
||||
|
||||
### 2. Add scope-aware path resolution for skills and commands
|
||||
|
||||
Refactor path resolution so both `init` and `update` compute install targets from:
|
||||
|
||||
- selected scope preference (`global` or `project`)
|
||||
- tool capability metadata (which scopes each tool/surface supports)
|
||||
- runtime context (project root, home directories, env overrides)
|
||||
|
||||
### 3. Add per-tool capability metadata for scope support
|
||||
|
||||
Extend tool metadata to explicitly declare scope support per surface:
|
||||
|
||||
- skills scope support
|
||||
- commands scope support
|
||||
|
||||
When preferred scope is unsupported for a tool/surface, the system uses deterministic fallback rules and reports the effective scope in output.
|
||||
|
||||
### 4. Make command generation context-aware
|
||||
|
||||
Extend command adapter path resolution so adapters receive install context (scope + environment context), instead of only command ID. This removes special-case handling and allows consistent scope behavior across tools.
|
||||
|
||||
### 5. Update init/update UX and behavior
|
||||
|
||||
- `openspec init`:
|
||||
- accepts scope override flag
|
||||
- uses configured scope or migration-aware default (new configs default global; legacy configs preserve project until migration)
|
||||
- applies scope-aware generation and cleanup planning
|
||||
- `openspec update`:
|
||||
- applies current scope preference
|
||||
- syncs artifacts in effective scope per tool/surface
|
||||
- tracks last successful effective scope per tool/surface for deterministic scope-drift detection
|
||||
- reports effective scope decisions clearly
|
||||
|
||||
### 6. Extend config UX and docs
|
||||
|
||||
- Add install scope control in `openspec config profile` interactive flow.
|
||||
- Extend `openspec config list` output with install scope source (`explicit`, `new-default`, `legacy-default`).
|
||||
- Add explicit migration guidance and prompt path so legacy users can opt into `global` scope.
|
||||
- Update supported tools and CLI docs to explain scope behavior and fallback rules.
|
||||
|
||||
### 7. Coordinate with command-surface capability delivery rules
|
||||
|
||||
`cli-init` and `cli-update` planning SHALL compose:
|
||||
|
||||
- install scope (`global | project`)
|
||||
- delivery mode (`both | skills | commands`)
|
||||
- command surface capability (`adapter | skills-invocable | none`)
|
||||
|
||||
This proposal remains focused on scope resolution, but implementation and test coverage should include mixed-tool cases to avoid regressions when combined with `add-tool-command-surface-capabilities`.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `installation-scope`: Scope preference model and effective scope resolution for tool artifact installation.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `global-config`: Persist install scope preference with schema evolution defaults.
|
||||
- `cli-config`: Configure and inspect install scope preferences.
|
||||
- `ai-tool-paths`: Add tool-level scope support metadata and path strategy.
|
||||
- `command-generation`: Scope-aware adapter path resolution via install context.
|
||||
- `cli-init`: Scope-aware initialization planning and output.
|
||||
- `cli-update`: Scope-aware update sync, drift detection, and output.
|
||||
- `migration`: Scope-aware migration scanning with install-scope-aware workflow lookup.
|
||||
|
||||
## Impact
|
||||
|
||||
- `src/core/global-config.ts` - new install scope fields and defaults
|
||||
- `src/core/config-schema.ts` - validation support for install scope config keys
|
||||
- `src/commands/config.ts` - interactive profile/config UX additions for install scope
|
||||
- `src/core/config.ts` - tool scope capability metadata
|
||||
- `src/core/available-tools.ts` and `src/core/shared/tool-detection.ts` - scope-aware configured detection
|
||||
- `src/core/command-generation/types.ts` and adapter implementations - context-aware file path resolution
|
||||
- `src/core/init.ts` - scope-aware generation/removal planning
|
||||
- `src/core/update.ts` - scope-aware sync/removal/drift planning
|
||||
- `src/core/migration.ts` - scope-aware workflow scanning support
|
||||
- `docs/supported-tools.md` and `docs/cli.md` - install scope behavior documentation
|
||||
- `test/core/init.test.ts`, `test/core/update.test.ts`, adapter tests, config tests - scope coverage
|
||||
@@ -0,0 +1,35 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: AIToolOption skillsDir field
|
||||
The `AIToolOption` interface SHALL include scope support metadata in addition to path metadata.
|
||||
|
||||
#### Scenario: Scope support metadata present
|
||||
- **WHEN** a tool entry is defined in `AI_TOOLS`
|
||||
- **THEN** it MAY declare supported install scopes for skills and commands
|
||||
- **AND** this metadata SHALL be used for effective scope resolution
|
||||
|
||||
#### Scenario: Scope support metadata absent
|
||||
- **WHEN** a tool entry in `AI_TOOLS` omits scope support metadata for a surface
|
||||
- **THEN** resolver behavior SHALL default that surface to project-only support
|
||||
- **AND** effective scope resolution SHALL apply normal preferred/fallback rules against that default
|
||||
|
||||
### Requirement: Path configuration for supported tools
|
||||
Path metadata SHALL support both project and global install targets via resolver logic.
|
||||
|
||||
#### Scenario: Project scope path
|
||||
- **WHEN** effective scope is `project` for skills
|
||||
- **THEN** `skillsDir` SHALL be treated as a tool-specific container path under project root
|
||||
- **AND** managed skill artifacts SHALL be written under `<projectRoot>/<skillsDir>/skills/`
|
||||
- **AND** tool definitions SHALL set `skillsDir` accordingly (for example `.openspec` -> `.openspec/skills/`)
|
||||
|
||||
#### Scenario: Global scope path
|
||||
- **WHEN** effective scope is `global` for a supported tool/surface
|
||||
- **THEN** paths SHALL resolve to tool-specific global directories
|
||||
- **AND** environment overrides (for example `CODEX_HOME`) SHALL be respected where applicable
|
||||
|
||||
#### Scenario: Windows global path resolution for Codex commands
|
||||
- **WHEN** effective scope is `global`
|
||||
- **AND** tool is Codex
|
||||
- **AND** platform is Windows
|
||||
- **THEN** command targets SHALL resolve to `%CODEX_HOME%\prompts` when `CODEX_HOME` is set
|
||||
- **AND** SHALL otherwise resolve to `%USERPROFILE%\.codex\prompts`
|
||||
@@ -0,0 +1,21 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Install scope configuration via profile flow
|
||||
The config profile workflow SHALL allow users to configure install scope preference.
|
||||
|
||||
#### Scenario: Interactive profile includes install scope
|
||||
- **WHEN** user runs `openspec config profile`
|
||||
- **THEN** the interactive flow SHALL include install scope selection with values `global` and `project`
|
||||
- **AND** the currently configured value SHALL be pre-selected
|
||||
|
||||
#### Scenario: Save install scope
|
||||
- **WHEN** user confirms config profile changes
|
||||
- **THEN** selected install scope SHALL be saved to global config
|
||||
|
||||
### Requirement: Install scope visibility in config output
|
||||
The config command SHALL display install scope preference in human-readable output.
|
||||
|
||||
#### Scenario: Config list shows install scope
|
||||
- **WHEN** user runs `openspec config list`
|
||||
- **THEN** output SHALL include current install scope value
|
||||
- **AND** indicate whether value is default or explicit
|
||||
@@ -0,0 +1,28 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Init install scope selection
|
||||
The init command SHALL support install scope selection for generated artifacts.
|
||||
|
||||
#### Scenario: Scope defaults to global
|
||||
- **WHEN** user runs `openspec init` without explicit scope override
|
||||
- **THEN** init SHALL use global config install scope
|
||||
- **AND** if unset, SHALL resolve migration-aware default (`global` for newly created configs, `project` for legacy schema-evolved configs)
|
||||
|
||||
#### Scenario: Scope override via flag
|
||||
- **WHEN** user runs `openspec init --scope project`
|
||||
- **THEN** init SHALL use `project` as preferred scope for that run
|
||||
- **AND** SHALL NOT mutate persisted global config unless user explicitly changes config
|
||||
|
||||
### Requirement: Init uses effective scope resolution
|
||||
The init command SHALL resolve effective scope per tool surface before generating files.
|
||||
|
||||
#### Scenario: Effective scope with fallback
|
||||
- **WHEN** selected tool/surface does not support preferred scope
|
||||
- **AND** supports alternate scope
|
||||
- **THEN** init SHALL generate files at alternate effective scope
|
||||
- **AND** SHALL display fallback note in summary
|
||||
|
||||
#### Scenario: Unsupported scope selection
|
||||
- **WHEN** selected tool/surface supports neither preferred nor alternate scope
|
||||
- **THEN** init SHALL fail before writing files
|
||||
- **AND** SHALL provide clear error guidance
|
||||
@@ -0,0 +1,34 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Update install scope selection
|
||||
The update command SHALL support install scope selection for sync operations.
|
||||
|
||||
#### Scenario: Scope defaults to global config value
|
||||
- **WHEN** user runs `openspec update` without explicit scope override
|
||||
- **THEN** update SHALL use configured install scope
|
||||
- **AND** if unset, SHALL resolve migration-aware default (`global` for newly created configs, `project` for legacy schema-evolved configs)
|
||||
|
||||
#### Scenario: Scope override via flag
|
||||
- **WHEN** user runs `openspec update --scope project`
|
||||
- **THEN** update SHALL use `project` as preferred scope for that run
|
||||
|
||||
### Requirement: Scope-aware sync and drift detection
|
||||
The update command SHALL evaluate configured state and drift using effective scoped paths.
|
||||
|
||||
#### Scenario: Scoped drift detection
|
||||
- **WHEN** update evaluates whether tools are up-to-date
|
||||
- **THEN** it SHALL inspect files at effective scoped targets for each tool/surface
|
||||
- **AND** SHALL compare current resolved scope against last successful effective scope for each tool/surface
|
||||
- **AND** SHALL treat a difference as sync-required drift
|
||||
|
||||
#### Scenario: Scope fallback during update
|
||||
- **WHEN** preferred scope is unsupported for a configured tool/surface
|
||||
- **AND** alternate scope is supported
|
||||
- **THEN** update SHALL apply fallback scope resolution
|
||||
- **AND** SHALL report fallback in output
|
||||
|
||||
#### Scenario: Unsupported scope during update
|
||||
- **WHEN** configured tool/surface supports neither preferred nor alternate scope
|
||||
- **THEN** scope support SHALL be validated for all configured tools/surfaces before any write
|
||||
- **AND** update SHALL fail without performing file writes when incompatibilities are detected
|
||||
- **AND** SHALL report incompatible tools with remediation steps
|
||||
@@ -0,0 +1,22 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: ToolCommandAdapter interface
|
||||
The system SHALL provide install-context-aware command path resolution.
|
||||
|
||||
#### Scenario: Adapter interface structure
|
||||
- **WHEN** implementing a tool adapter
|
||||
- **THEN** command file path resolution SHALL receive install context (including effective scope and environment context)
|
||||
- **AND** SHALL return the effective command output path for that context
|
||||
|
||||
#### Scenario: Codex global path remains supported
|
||||
- **WHEN** resolving Codex command paths in global scope
|
||||
- **THEN** the adapter SHALL target `$CODEX_HOME/prompts` when `CODEX_HOME` is set
|
||||
- **AND** SHALL otherwise target `~/.codex/prompts`
|
||||
|
||||
### Requirement: Command generator function
|
||||
The command generator SHALL pass install context into adapter path resolution for all generated commands.
|
||||
|
||||
#### Scenario: Scoped command generation
|
||||
- **WHEN** generating commands for a tool with a resolved effective scope
|
||||
- **THEN** generated command paths SHALL match that effective scope
|
||||
- **AND** the formatted command body/frontmatter behavior SHALL remain tool-specific and unchanged
|
||||
@@ -0,0 +1,24 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Install scope field in global config
|
||||
The global config schema SHALL include install scope preference.
|
||||
|
||||
#### Scenario: Config shape supports install scope
|
||||
- **WHEN** reading or writing global config
|
||||
- **THEN** config SHALL support `installScope` with allowed values `global` and `project`
|
||||
|
||||
#### Scenario: Schema evolution default
|
||||
- **WHEN** loading legacy config without `installScope`
|
||||
- **THEN** the system SHALL preserve schema compatibility without mutating the file
|
||||
- **AND** effective install scope SHALL resolve to `project` until user explicitly sets `installScope`
|
||||
- **AND** preserve all other existing fields
|
||||
|
||||
#### Scenario: New config default
|
||||
- **WHEN** creating a new global config
|
||||
- **THEN** the system SHALL persist `installScope: global` by default
|
||||
- **AND** users MAY switch to `project` explicitly
|
||||
|
||||
#### Scenario: Invalid install scope value
|
||||
- **WHEN** config validation receives an invalid install scope value
|
||||
- **THEN** the value SHALL be rejected
|
||||
- **AND** the system SHALL preserve the existing valid configuration
|
||||
@@ -0,0 +1,71 @@
|
||||
## Purpose
|
||||
|
||||
Define the install scope model for OpenSpec-generated skills and commands, including scope preference, effective scope resolution, and fallback/error semantics.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Install scope preference model
|
||||
The system SHALL support a user-level install scope preference with values `global` and `project`.
|
||||
|
||||
#### Scenario: Default install scope
|
||||
- **WHEN** install scope is not explicitly configured
|
||||
- **THEN** the system SHALL resolve a migration-aware default:
|
||||
- **AND** use `global` for newly created configs
|
||||
- **AND** use `project` for legacy schema-evolved configs until explicit migration
|
||||
|
||||
#### Scenario: Explicit install scope
|
||||
- **WHEN** user configures install scope to `project`
|
||||
- **THEN** generation and update flows SHALL use `project` as the preferred scope
|
||||
|
||||
### Requirement: Effective scope resolution by tool surface
|
||||
The system SHALL compute effective scope per tool surface (skills, commands) based on preferred scope and tool capability support.
|
||||
|
||||
#### Scenario: Preferred scope is supported
|
||||
- **WHEN** preferred scope is supported for a tool surface
|
||||
- **THEN** the system SHALL use that scope as the effective scope
|
||||
|
||||
#### Scenario: Preferred scope is unsupported but alternate is supported
|
||||
- **WHEN** preferred scope is not supported for a tool surface
|
||||
- **AND** the alternate scope is supported
|
||||
- **THEN** the system SHALL use the alternate scope as effective scope
|
||||
- **AND** SHALL record a fallback note for user-facing output
|
||||
|
||||
#### Scenario: No supported scope
|
||||
- **WHEN** neither `global` nor `project` is supported for a tool surface
|
||||
- **THEN** the command SHALL fail before writing files
|
||||
- **AND** SHALL display actionable remediation
|
||||
|
||||
### Requirement: Effective scope reporting
|
||||
The system SHALL report effective scope decisions in command output when they differ from the preferred scope.
|
||||
|
||||
#### Scenario: Fallback reporting
|
||||
- **WHEN** fallback resolution occurs for any selected/configured tool surface
|
||||
- **THEN** init/update summaries SHALL include effective scope notes per affected tool
|
||||
|
||||
### Requirement: Cross-platform path behavior
|
||||
Install scope resolution SHALL produce platform-correct target paths.
|
||||
|
||||
#### Scenario: Global scope path on Windows
|
||||
- **WHEN** effective scope is `global`
|
||||
- **AND** the command runs on Windows
|
||||
- **THEN** resolved target paths SHALL use Windows path conventions and separators
|
||||
- **AND** SHALL NOT reuse POSIX-style home-relative defaults directly
|
||||
|
||||
### Requirement: Cleanup safety for scope transitions
|
||||
Scope transitions SHALL update new targets first and clean old managed targets safely.
|
||||
|
||||
#### Scenario: Automatic cleanup for managed files on scope change
|
||||
- **WHEN** update or init applies a scope transition for a configured tool/surface
|
||||
- **THEN** the system SHALL write new artifacts in the new effective scope before cleanup
|
||||
- **AND** SHALL automatically remove only OpenSpec-managed files in the previous effective scope
|
||||
|
||||
#### Scenario: Cleanup scope boundaries
|
||||
- **WHEN** cleanup runs after a scope transition
|
||||
- **THEN** the system SHALL leave non-managed files untouched
|
||||
- **AND** SHALL limit removal scope to the affected tool/workflow-managed paths
|
||||
|
||||
#### Scenario: Cleanup failure after successful writes
|
||||
- **WHEN** new artifacts were written successfully in the new scope
|
||||
- **AND** cleanup of old managed targets fails
|
||||
- **THEN** the command SHALL report failure with leftover cleanup paths
|
||||
- **AND** SHALL NOT rollback successfully written new-scope artifacts
|
||||
@@ -0,0 +1,61 @@
|
||||
## 1. Global Config + Validation
|
||||
|
||||
- [ ] 1.1 Add `installScope` (`global` | `project`) to `GlobalConfig` with explicit `global` default for newly created configs
|
||||
- [ ] 1.2 Update config schema validation and known-key checks to include install scope
|
||||
- [ ] 1.3 Add schema-evolution tests ensuring missing `installScope` in legacy configs resolves to effective `project` until explicit migration
|
||||
- [ ] 1.4 Extend `openspec config list` output to show install scope and source (`explicit`, `new-default`, `legacy-default`)
|
||||
|
||||
## 2. Tool Capability Metadata + Resolvers
|
||||
|
||||
- [ ] 2.1 Extend `AI_TOOLS` metadata to declare scope support per surface (skills/commands)
|
||||
- [ ] 2.2 Add shared install-target resolver for skills and commands using requested scope + tool support
|
||||
- [ ] 2.3 Implement deterministic fallback/error behavior when preferred scope is unsupported, including default behavior when scope support metadata is absent
|
||||
- [ ] 2.4 Add unit tests for scope resolution (preferred, fallback, and hard-fail paths)
|
||||
|
||||
## 3. Command Generation Contract
|
||||
|
||||
- [ ] 3.1 Update `ToolCommandAdapter` path contract to accept install context
|
||||
- [ ] 3.2 Update `generateCommand`/`generateCommands` to pass context through adapters
|
||||
- [ ] 3.3 Migrate all command adapters to the new path contract
|
||||
- [ ] 3.4 Update adapter tests for scoped path behavior (including Codex global path semantics)
|
||||
|
||||
## 4. Init Command Scope Support
|
||||
|
||||
- [ ] 4.1 Add scope override flag to `openspec init` (`--scope global|project`)
|
||||
- [ ] 4.2 Resolve effective scope per tool/surface before writing artifacts
|
||||
- [ ] 4.3 Apply scope-aware generation/removal planning for skills and commands
|
||||
- [ ] 4.4 Surface effective scope decisions and fallback notes in init summary output
|
||||
- [ ] 4.5 Add init tests for global default, project override, and fallback/error scenarios
|
||||
|
||||
## 5. Update Command Scope Support
|
||||
|
||||
- [ ] 5.1 Add scope override flag to `openspec update` (`--scope global|project`)
|
||||
- [ ] 5.2 Make configured-tool detection and drift checks scope-aware
|
||||
- [ ] 5.3 Persist and read last successful effective scope per tool/surface for deterministic scope-drift detection
|
||||
- [ ] 5.4 Apply scope-aware sync/removal with consistent fallback/error behavior
|
||||
- [ ] 5.5 Ensure scope changes update managed files in new targets and clean old managed targets safely
|
||||
- [ ] 5.6 Add update tests for global/project/fallback/error and repeat-run idempotency
|
||||
|
||||
## 6. Config UX
|
||||
|
||||
- [ ] 6.1 Extend `openspec config profile` interactive flow to select install scope
|
||||
- [ ] 6.2 Preserve install scope when using preset shortcuts unless explicitly changed
|
||||
- [ ] 6.3 Ensure non-interactive config behavior remains deterministic with clear errors
|
||||
- [ ] 6.4 Add/adjust config command tests for install scope flows
|
||||
- [ ] 6.5 Add migration UX for legacy users to opt into `global` scope explicitly
|
||||
|
||||
## 7. Documentation
|
||||
|
||||
- [ ] 7.1 Update `docs/supported-tools.md` with scope behavior and effective-scope fallback notes
|
||||
- [ ] 7.2 Update `docs/cli.md` examples for init/update scope options
|
||||
- [ ] 7.3 Document cross-project implications of global installs
|
||||
- [ ] 7.4 Add existing-user migration guide covering legacy-default behavior and explicit opt-in to `installScope: global`
|
||||
|
||||
## 8. Verification
|
||||
|
||||
- [ ] 8.1 Run targeted tests for config, adapters, init, and update
|
||||
- [ ] 8.2 Run full test suite (`pnpm test`) and resolve regressions
|
||||
- [ ] 8.3 Manual smoke test: init/update with `installScope=global`
|
||||
- [ ] 8.4 Manual smoke test: init/update with `--scope project`
|
||||
- [ ] 8.5 Verify path resolution behavior on Windows CI (or cross-platform unit tests with mocked Windows paths)
|
||||
- [ ] 8.6 Verify combined behavior matrix for mixed tools across scope × delivery × command-surface capability
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-20
|
||||
@@ -0,0 +1,45 @@
|
||||
## Why
|
||||
|
||||
We need a faster, more reliable way to manually validate CLI behavior changes like profile/delivery sync, migration behavior, and tool-detection UX.
|
||||
|
||||
Today, manual review is mostly ad hoc: each developer sets up state differently, runs a different command order, and checks outputs informally. This makes regressions easy to miss and slows iteration on CLI UX work.
|
||||
|
||||
An 80/20 solution is to add a lightweight smoke harness for deterministic non-interactive flows, plus a short manual checklist for interactive prompt behavior.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add a lightweight QA smoke harness for OpenSpec CLI behavior with isolated per-run sandbox state
|
||||
- Use `Makefile` targets as the primary entrypoint:
|
||||
- `make qa` (default local QA entrypoint)
|
||||
- `make qa-smoke` (deterministic non-interactive suite)
|
||||
- `make qa-interactive` (prints/opens manual interactive checklist)
|
||||
- Implement smoke logic in a script (invoked by Make targets), not in Make itself
|
||||
- Ensure each scenario runs in an isolated sandbox with temporary `HOME`, `XDG_CONFIG_HOME`, `XDG_DATA_HOME`, and `CODEX_HOME`
|
||||
- Capture scenario artifacts for inspection (command output, exit code, and before/after filesystem state)
|
||||
- Add a focused scenario set for high-risk behavior:
|
||||
- init core output generation
|
||||
- non-interactive detected-tool behavior
|
||||
- migration when profile is unset
|
||||
- delivery cleanup (`both -> skills`, `both -> commands`)
|
||||
- commands-only update detection
|
||||
- new tool directory detection messaging
|
||||
- invalid profile override validation
|
||||
- Add a short interactive checklist for keypress/prompt UX verification (Space toggle, Enter confirm, detected pre-selection)
|
||||
- Wire CI to run the smoke suite on Linux as a fast regression gate
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `qa-smoke-harness`: Deterministic, sandboxed CLI smoke validation with a single developer entrypoint
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `developer-qa-workflow`: Standardized local/CI QA flow for CLI behavior and migration-sensitive scenarios
|
||||
|
||||
## Impact
|
||||
|
||||
- `Makefile` - Add `qa`, `qa-smoke`, and `qa-interactive` targets
|
||||
- `scripts/qa-smoke.sh` (or equivalent) - Implement sandbox setup, scenario execution, and assertions
|
||||
- `docs/` - Add/update contributor-facing QA instructions and interactive checklist usage
|
||||
- CI workflow - Add smoke target execution as a lightweight regression gate
|
||||
@@ -0,0 +1,49 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Makefile QA Entry Point
|
||||
|
||||
The repository SHALL provide Makefile targets as the primary developer entrypoint for CLI QA flows.
|
||||
|
||||
#### Scenario: Default QA target runs smoke suite
|
||||
|
||||
- **WHEN** a developer runs `make qa`
|
||||
- **THEN** the command SHALL execute the non-interactive smoke suite
|
||||
- **AND** exit with status code 0 only when all smoke scenarios pass
|
||||
|
||||
#### Scenario: Smoke suite target is directly invokable
|
||||
|
||||
- **WHEN** a developer runs `make qa-smoke`
|
||||
- **THEN** the command SHALL execute the same smoke suite used by `make qa`
|
||||
- **AND** return a non-zero exit code on assertion failure
|
||||
|
||||
#### Scenario: Interactive checklist target exists
|
||||
|
||||
- **WHEN** a developer runs `make qa-interactive`
|
||||
- **THEN** the command SHALL provide the manual interactive verification checklist
|
||||
- **AND** SHALL NOT run interactive prompt automation by default
|
||||
|
||||
### Requirement: Sandboxed Smoke Scenario Runner
|
||||
|
||||
The smoke suite SHALL run CLI scenarios in isolated sandboxes so tests are repeatable and do not depend on machine-global state.
|
||||
|
||||
#### Scenario: Scenario execution is environment-isolated
|
||||
|
||||
- **WHEN** a smoke scenario runs
|
||||
- **THEN** it SHALL use temporary values for `HOME`, `XDG_CONFIG_HOME`, `XDG_DATA_HOME`, and `CODEX_HOME`
|
||||
- **AND** global config from the host machine SHALL NOT affect scenario outcomes
|
||||
|
||||
#### Scenario: Scenario artifacts are captured for review
|
||||
|
||||
- **WHEN** a smoke scenario completes
|
||||
- **THEN** the runner SHALL capture command output and exit status
|
||||
- **AND** SHALL capture enough filesystem state to inspect before/after behavior
|
||||
|
||||
#### Scenario: High-risk workflow coverage exists
|
||||
|
||||
- **WHEN** the smoke suite executes
|
||||
- **THEN** it SHALL include scenarios covering profile/delivery behavior and migration-sensitive flows
|
||||
- **AND** include at least:
|
||||
- non-interactive tool detection
|
||||
- migration when profile is unset
|
||||
- delivery cleanup (`both -> skills`, `both -> commands`)
|
||||
- commands-only update detection
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-19
|
||||
@@ -0,0 +1,111 @@
|
||||
## Why
|
||||
|
||||
OpenSpec currently assumes command delivery maps directly to command adapters. That assumption does not hold for all tools.
|
||||
|
||||
Trae is a concrete example: it invokes OpenSpec workflows via skill entries (for example `/openspec-new-change`) rather than adapter-generated command files. In this model, skills are the command surface.
|
||||
|
||||
Today, this creates a behavior gap:
|
||||
|
||||
- `delivery=commands` can remove skills
|
||||
- tools without adapters skip command generation
|
||||
- result: selected tools like Trae can end up with no invocable workflow artifacts
|
||||
|
||||
This is more than a prompt UX issue because non-interactive and CI flows bypass interactive guidance. We need a capability-aware model in core generation logic.
|
||||
|
||||
## What Changes
|
||||
|
||||
### 1. Add explicit command-surface capability metadata
|
||||
|
||||
Add an optional field in tool metadata to describe how a tool exposes commands:
|
||||
|
||||
- `adapter`: command files are generated through a command adapter
|
||||
- `skills-invocable`: skills are directly invocable as commands
|
||||
- `none`: no OpenSpec command surface
|
||||
|
||||
Field should be optional. Default behavior is inferred from adapter registry presence: tools with a registered adapter resolve to `adapter`; tools with no adapter registration and no explicit annotation resolve to `none`.
|
||||
Capability values use kebab-case string tokens for consistency with serialized metadata conventions.
|
||||
|
||||
Initial explicit override:
|
||||
|
||||
- Trae -> `skills-invocable`
|
||||
|
||||
### 2. Make delivery behavior capability-aware
|
||||
|
||||
Update `init` and `update` to compute effective artifact actions per tool from:
|
||||
|
||||
- global delivery (`both | skills | commands`)
|
||||
- tool command surface capability
|
||||
|
||||
Behavior matrix:
|
||||
|
||||
- `both`:
|
||||
- generate skills for all tools with `skillsDir` (including `skills-invocable`)
|
||||
- generate command files only for `adapter` tools
|
||||
- `none`: no artifact action; MAY emit compatibility warning
|
||||
- `skills`:
|
||||
- generate skills for all tools with `skillsDir` (including `skills-invocable`)
|
||||
- remove adapter-generated command files
|
||||
- `none`: no artifact action; MAY emit compatibility warning
|
||||
- `commands`:
|
||||
- `adapter`: generate commands, remove skills
|
||||
- `skills-invocable`: generate (or keep if up-to-date) skills as command surface; do not remove them
|
||||
- `none`: fail fast with clear error
|
||||
|
||||
### 3. Add preflight validation and clearer output
|
||||
|
||||
Before writing/removing artifacts, validate selected/configured tools against delivery mode:
|
||||
|
||||
- interactive flow: show clear compatibility note before confirmation
|
||||
- non-interactive flow: fail with deterministic error listing incompatible tools and supported alternatives
|
||||
|
||||
Update summaries to show effective delivery outcomes per tool (for example, when commands mode still installs skills for skills-invocable tools).
|
||||
|
||||
### 4. Update docs and tests
|
||||
|
||||
- document capability model and Trae behavior under delivery modes
|
||||
- ensure CLI docs and supported-tools docs reflect effective behavior
|
||||
- add test coverage for:
|
||||
- `init --tools trae` with `delivery=commands`
|
||||
- `update` with Trae configured under `delivery=commands`
|
||||
- mixed selections (`claude + trae`) across all delivery modes
|
||||
- explicit error path for tools with no command surface under `delivery=commands`
|
||||
|
||||
### 5. Coordinate with install-scope behavior
|
||||
|
||||
When combined with `add-global-install-scope`, init/update planning must compose:
|
||||
|
||||
- install scope (`global | project`)
|
||||
- delivery mode (`both | skills | commands`)
|
||||
- command surface capability (`adapter | skills-invocable | none`)
|
||||
|
||||
Implementation tests should cover mixed-tool matrices to ensure deterministic behavior when both changes are active.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `tool-command-surface`: Capability model that classifies tools as `adapter`, `skills-invocable`, or `none` to drive delivery behavior
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `cli-init`: Delivery handling becomes tool-capability-aware with preflight compatibility validation
|
||||
- `cli-update`: Delivery sync becomes tool-capability-aware with consistent compatibility validation and messaging
|
||||
- `supported-tools-docs`: Documents command-surface semantics for non-adapter tools
|
||||
|
||||
## Impact
|
||||
|
||||
- `src/core/config.ts` - add optional command-surface metadata and Trae override
|
||||
- `src/core/command-generation/registry.ts` (or shared helper) - capability inference from adapter presence
|
||||
- `src/core/init.ts` - capability-aware generation/removal planning + compatibility validation + summary messaging
|
||||
- `src/core/update.ts` - capability-aware sync/removal planning + compatibility validation + summary messaging
|
||||
- `src/core/shared/tool-detection.ts` - include capability-aware detection so `skills-invocable` tools remain detectable under `delivery=commands`, and `none` tools are excluded from command-surface artifact detection
|
||||
- `docs/supported-tools.md` and `docs/cli.md` - document delivery behavior and compatibility notes
|
||||
- `test/core/init.test.ts` and `test/core/update.test.ts` - add coverage for skills-invocable behavior and mixed-tool delivery scenarios
|
||||
|
||||
## Sequencing Notes
|
||||
|
||||
- This change is intended to stack safely with `simplify-skill-installation` by introducing additive, capability-specific requirements for init/update.
|
||||
- If `simplify-skill-installation` merges first, this change should be rebased and keep the capability-aware rule as the source of truth for `delivery=commands` behavior on `skills-invocable` tools.
|
||||
- If this change merges first, the `simplify-skill-installation` branch should be rebased to avoid re-introducing a global "commands-only means no skills for all tools" assumption.
|
||||
- If `add-global-install-scope` merges first, this change should be rebased to compose capability-aware behavior on top of scope-resolved path decisions from that change.
|
||||
- If this change merges first, `add-global-install-scope` should be rebased to preserve Section 5 composition rules (`install scope` + `delivery mode` + `command surface capability`) without overriding capability-aware command-surface outcomes.
|
||||
@@ -0,0 +1,121 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Command surface capability resolution
|
||||
The init command SHALL resolve each selected tool's command surface using explicit metadata first, then deterministic inference.
|
||||
|
||||
#### Scenario: Explicit command surface override
|
||||
- **WHEN** a tool declares an explicit command-surface capability
|
||||
- **THEN** init SHALL use that explicit capability
|
||||
- **AND** SHALL NOT override it based on adapter presence
|
||||
|
||||
#### Scenario: Inferred command surface from adapter presence
|
||||
- **WHEN** a tool does not declare an explicit command-surface capability
|
||||
- **AND** a command adapter is registered for the tool
|
||||
- **THEN** init SHALL infer `adapter` as the command surface
|
||||
|
||||
#### Scenario: Inferred command surface for skills-only tool
|
||||
- **WHEN** a tool does not declare an explicit command-surface capability
|
||||
- **AND** no command adapter is registered for the tool
|
||||
- **AND** the tool has a configured `skillsDir`
|
||||
- **THEN** init SHALL infer `skills-invocable` as the command surface
|
||||
|
||||
#### Scenario: Inferred command surface without adapter or skills
|
||||
- **WHEN** a tool does not declare an explicit command-surface capability
|
||||
- **AND** no command adapter is registered for the tool
|
||||
- **AND** the tool has no `skillsDir`
|
||||
- **THEN** init SHALL infer `none` as the command surface
|
||||
|
||||
### Requirement: Delivery compatibility by tool command surface
|
||||
The init command SHALL apply delivery settings using each tool's command surface capability, not adapter presence alone.
|
||||
|
||||
#### Scenario: Both delivery for adapter-backed tool
|
||||
- **WHEN** user runs `openspec init` with a selected tool that has a command adapter
|
||||
- **AND** delivery is set to `both`
|
||||
- **THEN** the system SHALL generate command files for active workflows using that adapter
|
||||
- **AND** SHALL generate or refresh managed skills when the tool has `skillsDir`
|
||||
|
||||
#### Scenario: Both delivery for skills-invocable tool
|
||||
- **WHEN** user runs `openspec init` with a selected tool whose command surface is `skills-invocable`
|
||||
- **AND** delivery is set to `both`
|
||||
- **THEN** the system SHALL generate or refresh managed skill directories when the tool has `skillsDir`
|
||||
- **AND** SHALL NOT require adapter-generated command files for that tool
|
||||
|
||||
#### Scenario: Both delivery for none command surface
|
||||
- **WHEN** user runs `openspec init` with a selected tool whose command surface is `none`
|
||||
- **AND** delivery is set to `both`
|
||||
- **THEN** the system SHALL perform no command-surface artifact action for that tool
|
||||
- **AND** MAY emit a compatibility note indicating no command surface is available
|
||||
|
||||
#### Scenario: Skills delivery for adapter-backed tool
|
||||
- **WHEN** user runs `openspec init` with a selected tool that has a command adapter
|
||||
- **AND** delivery is set to `skills`
|
||||
- **THEN** the system SHALL generate or refresh managed skill directories when the tool has `skillsDir`
|
||||
- **AND** SHALL remove managed adapter-generated command files for that tool
|
||||
|
||||
#### Scenario: Skills delivery for skills-invocable tool
|
||||
- **WHEN** user runs `openspec init` with a selected tool whose command surface is `skills-invocable`
|
||||
- **AND** delivery is set to `skills`
|
||||
- **THEN** the system SHALL generate or refresh managed skill directories when the tool has `skillsDir`
|
||||
- **AND** SHALL NOT require adapter-generated command files for that tool
|
||||
|
||||
#### Scenario: Skills delivery for none command surface
|
||||
- **WHEN** user runs `openspec init` with a selected tool whose command surface is `none`
|
||||
- **AND** delivery is set to `skills`
|
||||
- **THEN** the system SHALL perform no command-surface artifact action for that tool
|
||||
- **AND** MAY emit a compatibility note indicating no command surface is available
|
||||
|
||||
#### Scenario: Commands delivery for adapter-backed tool
|
||||
- **WHEN** user runs `openspec init` with a selected tool that has a command adapter
|
||||
- **AND** delivery is set to `commands`
|
||||
- **THEN** the system SHALL generate command files for active workflows using that adapter
|
||||
- **AND** the system SHALL remove managed skill directories for that tool
|
||||
|
||||
#### Scenario: Commands delivery for skills-invocable tool
|
||||
- **WHEN** user runs `openspec init` with a selected tool whose command surface is `skills-invocable`
|
||||
- **AND** delivery is set to `commands`
|
||||
- **THEN** the system SHALL generate or refresh managed skill directories for active workflows
|
||||
- **AND** the system SHALL NOT remove those managed skill directories as part of commands-only cleanup
|
||||
- **AND** the system SHALL NOT require a command adapter for that tool
|
||||
|
||||
#### Scenario: Commands delivery for mixed tool selection
|
||||
- **WHEN** user runs `openspec init` with multiple tools
|
||||
- **AND** selected tools include both adapter-backed and skills-invocable command surfaces
|
||||
- **AND** delivery is set to `commands`
|
||||
- **THEN** the system SHALL apply commands-only behavior per tool capability
|
||||
- **AND** the resulting install SHALL include command files for adapter-backed tools and skills for skills-invocable tools
|
||||
|
||||
#### Scenario: Commands delivery for unsupported command surface
|
||||
- **WHEN** user runs `openspec init` with a selected tool that has no command surface capability
|
||||
- **AND** delivery is set to `commands`
|
||||
- **THEN** the system SHALL fail before generating or deleting artifacts
|
||||
- **AND** the error SHALL list incompatible tool IDs and explain supported alternatives (`both` or `skills`)
|
||||
|
||||
#### Scenario: Interactive handling for unsupported command surface
|
||||
- **WHEN** user runs `openspec init` interactively
|
||||
- **AND** delivery is set to `commands`
|
||||
- **AND** selected tools include one or more tools with command surface `none`
|
||||
- **THEN** the CLI SHALL show a compatibility error and return to the interactive selection flow for correction
|
||||
- **AND** SHALL not perform artifact writes until a valid selection is confirmed
|
||||
|
||||
### Requirement: Init compatibility signaling
|
||||
The init command SHALL clearly signal command-surface compatibility outcomes in both interactive and non-interactive flows.
|
||||
|
||||
#### Scenario: Interactive compatibility note
|
||||
- **WHEN** init runs interactively
|
||||
- **AND** delivery is `commands`
|
||||
- **AND** selected tools include skills-invocable command surfaces
|
||||
- **THEN** the system SHALL display a compatibility note before the confirmation prompt indicating those tools will use skills as their command surface
|
||||
|
||||
#### Scenario: Non-interactive compatibility summary for skills-invocable tools
|
||||
- **WHEN** init runs non-interactively (including `--tools` usage)
|
||||
- **AND** delivery is `commands`
|
||||
- **AND** selected tools include one or more `skills-invocable` command surfaces
|
||||
- **THEN** the command SHALL proceed with exit code 0
|
||||
- **AND** the command SHALL write deterministic compatibility summary lines to stdout indicating those tools will use managed skills as their command surface
|
||||
|
||||
#### Scenario: Non-interactive compatibility failure
|
||||
- **WHEN** init runs non-interactively (including `--tools` usage)
|
||||
- **AND** delivery is `commands`
|
||||
- **AND** selected tools include any tool with no command surface capability
|
||||
- **THEN** the command SHALL exit with code 1
|
||||
- **AND** the command SHALL write deterministic, actionable guidance for resolving the selection to stderr
|
||||
@@ -0,0 +1,48 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Delivery sync by command surface capability
|
||||
The update command SHALL synchronize artifacts using each configured tool's command surface capability.
|
||||
|
||||
#### Scenario: Commands delivery for adapter-backed configured tool
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** delivery is set to `commands`
|
||||
- **AND** a configured tool has an adapter-backed command surface
|
||||
- **THEN** the system SHALL generate or refresh command files for active workflows
|
||||
- **AND** the system SHALL remove managed skill directories for that tool
|
||||
|
||||
#### Scenario: Commands delivery for skills-invocable configured tool
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** delivery is set to `commands`
|
||||
- **AND** a configured tool has `skills-invocable` command surface capability
|
||||
- **THEN** the system SHALL generate or refresh managed skill directories for active workflows
|
||||
- **AND** the system SHALL NOT remove those managed skill directories as part of commands-only cleanup
|
||||
- **AND** the system SHALL NOT attempt to require adapter-generated command files for that tool
|
||||
|
||||
#### Scenario: Commands delivery with unsupported command surface
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** delivery is set to `commands`
|
||||
- **AND** a configured tool has no command surface capability
|
||||
- **THEN** the system SHALL fail with exit code 1 before applying partial updates
|
||||
- **AND** the output SHALL identify incompatible tools and recommended remediation
|
||||
|
||||
### Requirement: Configured-tool detection for skills-invocable command surfaces
|
||||
The update command SHALL treat tools with skills-invocable command surfaces as configured when managed skill artifacts are present, including under commands delivery.
|
||||
|
||||
#### Scenario: Skills-invocable tool under commands delivery
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** delivery is set to `commands`
|
||||
- **AND** a tool has no adapter-generated command files
|
||||
- **AND** that tool is marked `skills-invocable` and has managed skills installed
|
||||
- **THEN** the system SHALL include the tool in configured-tool detection
|
||||
- **AND** the system SHALL apply normal version/profile/delivery sync to that tool
|
||||
|
||||
### Requirement: Update summary reflects effective per-tool delivery
|
||||
The update command SHALL report effective artifact behavior when delivery intent and artifact type differ due to tool capability.
|
||||
|
||||
#### Scenario: Summary for skills-invocable tools in commands delivery
|
||||
- **WHEN** update completes successfully
|
||||
- **AND** delivery is `commands`
|
||||
- **AND** at least one updated tool is `skills-invocable`
|
||||
- **THEN** output SHALL include a clear note that those tools use skills as their command surface
|
||||
- **AND** output SHALL avoid implying that command generation was skipped due to an error
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
## 0. Stacking Coordination
|
||||
|
||||
- [ ] 0.1 Rebase this change on latest `main` before implementation
|
||||
- [ ] 0.2 If `simplify-skill-installation` is merged first, preserve its profile/delivery model and apply this change as a capability-aware refinement
|
||||
- [ ] 0.3 If this change merges first, ensure follow-up rebases do not reintroduce a blanket "commands = remove all skills" rule
|
||||
- [ ] 0.4 If `add-global-install-scope` is merged, verify combined scope × delivery × command-surface behavior remains deterministic
|
||||
|
||||
## 1. Tool Command-Surface Capability Model
|
||||
|
||||
- [ ] 1.1 Extend tool metadata in `src/core/config.ts` with an optional command-surface capability field
|
||||
- [ ] 1.2 Define supported capability values: `adapter`, `skills-invocable`, `none`
|
||||
- [ ] 1.3 Mark Trae as `skills-invocable`
|
||||
- [ ] 1.4 Add a shared capability resolver (explicit metadata override first, inferred fallback from adapter presence second)
|
||||
- [ ] 1.5 Add focused unit tests for capability resolution (explicit override, inferred adapter, inferred none)
|
||||
|
||||
## 2. Init: Capability-Aware Delivery Planning
|
||||
|
||||
- [ ] 2.1 Refactor init generation logic to compute per-tool effective actions (generate/remove skills and commands) instead of using only global booleans
|
||||
- [ ] 2.2 In `delivery=commands`, keep/generate skills for `skills-invocable` tools and do not remove those managed skill directories
|
||||
- [ ] 2.3 In `delivery=commands`, fail fast before writes when any selected tool resolves to `none`
|
||||
- [ ] 2.4 Update init output to clearly report effective behavior for `skills-invocable` tools (skills used as command surface)
|
||||
- [ ] 2.5 Ensure init no longer reports "no adapter" for tools intentionally using `skills-invocable`
|
||||
- [ ] 2.6 Add/adjust init tests for `delivery=commands` + `trae` (skills retained/generated, no adapter error), mixed tools (`claude,trae`) with per-tool expected outputs, and deterministic failure path for unsupported command surface (`none`)
|
||||
|
||||
## 3. Update: Capability-Aware Sync and Drift Detection
|
||||
|
||||
- [ ] 3.1 Refactor update sync logic to apply delivery behavior per tool capability (not globally per run)
|
||||
- [ ] 3.2 In `delivery=commands`, keep/generate managed skills for `skills-invocable` tools
|
||||
- [ ] 3.3 In `delivery=commands`, fail before partial updates when configured tools include a `none` command surface
|
||||
- [ ] 3.4 Update profile/delivery drift detection to avoid perpetual drift for `skills-invocable` tools under commands delivery
|
||||
- [ ] 3.5 Ensure configured-tool detection still includes `skills-invocable` tools under commands delivery when managed skills exist
|
||||
- [ ] 3.6 Update summary output so skills-invocable behavior is reported as expected behavior (not implicit skip/error)
|
||||
- [ ] 3.7 Add/adjust update tests for `delivery=commands` + configured Trae (skills retained/generated), idempotent second update (no false drift loop), mixed configured tools (`claude` + `trae`), and deterministic preflight failure for unsupported command surface (`none`)
|
||||
|
||||
## 4. UX and Error Messaging
|
||||
|
||||
- [ ] 4.1 Add interactive init compatibility note for `delivery=commands` when selected tools include `skills-invocable`
|
||||
- [ ] 4.2 Add deterministic non-interactive error text with incompatible tool IDs and suggested alternatives (`both` or `skills`)
|
||||
- [ ] 4.3 Align init and update wording so capability-related behavior/messages are consistent
|
||||
|
||||
## 5. Documentation Updates
|
||||
|
||||
- [ ] 5.1 Update `docs/supported-tools.md` to document command-surface semantics for Trae and clarify delivery interactions
|
||||
- [ ] 5.2 Update `docs/cli.md` delivery guidance to explain capability-aware behavior for `delivery=commands`
|
||||
- [ ] 5.3 Add a short troubleshooting note for "commands-only + unsupported tool" failures
|
||||
|
||||
## 6. Verification
|
||||
|
||||
- [ ] 6.1 Run targeted tests: `test/core/init.test.ts` and `test/core/update.test.ts`
|
||||
- [ ] 6.2 Run any new capability/unit test files added in this change
|
||||
- [ ] 6.3 Run full test suite (`pnpm test`) and resolve regressions
|
||||
- [ ] 6.4 Manual smoke check: `openspec init --tools trae` with `delivery=commands`
|
||||
- [ ] 6.5 Manual smoke check: mixed tools (`claude,trae`) with `delivery=commands`
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-01-30
|
||||
@@ -0,0 +1,3 @@
|
||||
# opencode-command-references
|
||||
|
||||
Transform /opsx: to /opsx- in both commands and skills for OpenCode
|
||||
@@ -0,0 +1,70 @@
|
||||
## Context
|
||||
|
||||
OpenCode is one of many supported AI tools. Each tool has:
|
||||
- A **command adapter** (in `src/core/command-generation/adapters/`) for generating tool-specific command files
|
||||
- **Skills** generated via `generateSkillContent()` in `src/core/shared/skill-generation.ts`
|
||||
|
||||
Currently:
|
||||
- Commands go through the adapter system which can transform content per-tool
|
||||
- Skills use a single shared function with no tool-specific transformation
|
||||
|
||||
The templates in `src/core/templates/skill-templates.ts` use Claude's colon-based format (`/opsx:new`) as the canonical format. Tools that use different formats need transformation at generation time.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Transform all `/opsx:` command references to `/opsx-` for OpenCode in both commands and skills
|
||||
- Create a shared, reusable transformation utility
|
||||
- Keep the transformation opt-in via a callback parameter (not hard-coded tool detection)
|
||||
|
||||
**Non-Goals:**
|
||||
- Modifying the canonical template format (templates stay with `/opsx:`)
|
||||
- Applying transformation to other tools (only OpenCode for now)
|
||||
- Creating a full adapter system for skills (overkill for current needs)
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision 1: Shared Utility Function
|
||||
|
||||
**Choice**: Create `transformToHyphenCommands()` in `src/utils/command-references.ts`
|
||||
|
||||
**Rationale**:
|
||||
- Single source of truth for the transformation logic
|
||||
- Can be used by both command adapter and skill generation
|
||||
- Easy to test in isolation
|
||||
- Follows existing utils pattern in the codebase
|
||||
|
||||
**Alternatives considered**:
|
||||
- Inline the transformation in each location - Duplicates logic, harder to maintain
|
||||
|
||||
### Decision 2: Callback Parameter for Skill Generation
|
||||
|
||||
**Choice**: Add optional `transformInstructions?: (instructions: string) => string` parameter to `generateSkillContent()`
|
||||
|
||||
**Rationale**:
|
||||
- Flexible - callers define the transformation, not the generation function
|
||||
- No coupling - `generateSkillContent()` doesn't need to know about tool formats
|
||||
- Extensible - could support other transformations in the future
|
||||
- Follows inversion of control principle
|
||||
|
||||
**Alternatives considered**:
|
||||
- Add tool ID parameter and switch on it - Creates coupling, harder to extend
|
||||
- Create skill adapter system parallel to commands - Over-engineering for current needs
|
||||
- Transform in templates directly - Breaks single-source-of-truth principle
|
||||
|
||||
### Decision 3: Apply at Generation Sites
|
||||
|
||||
**Choice**: Pass transformer in `init.ts` and `update.ts` when `tool.value === 'opencode'`
|
||||
|
||||
**Rationale**:
|
||||
- These are the only two places that generate skills
|
||||
- Simple conditional check, no new abstractions needed
|
||||
- Easy to extend to other tools if needed later
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| Other `/opsx:` patterns exist that shouldn't be transformed | All occurrences in templates are command invocations - verified by inspection |
|
||||
| Future tools may need same transformation | Utility is shared and easy to reuse; can add to other tools' generation |
|
||||
| Callback adds complexity to function signature | Optional parameter with sensible default (no transformation) |
|
||||
@@ -0,0 +1,32 @@
|
||||
## Why
|
||||
|
||||
OpenCode uses hyphen-based command syntax (`/opsx-new`) but our templates contain colon-based references (`/opsx:new`). This creates inconsistency where generated command files and skill files contain references that don't match the actual command invocation syntax, confusing both the AI and users.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Create a shared transformation utility (`transformToHyphenCommands`) for converting `/opsx:` to `/opsx-`
|
||||
- Update the OpenCode command adapter to transform body text using this utility
|
||||
- Add an optional `transformInstructions` callback parameter to `generateSkillContent()`
|
||||
- Update `init.ts` and `update.ts` to pass the transformer when generating skills for OpenCode
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
None - this is a bug fix, not a new capability.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
None - no spec-level behavior changes. This is an implementation fix in the OpenCode adapter and skill generation that doesn't change any external requirements or contracts.
|
||||
|
||||
## Impact
|
||||
|
||||
- **Code**:
|
||||
- `src/utils/command-references.ts` (new file)
|
||||
- `src/utils/index.ts` (export)
|
||||
- `src/core/shared/skill-generation.ts` (add callback parameter)
|
||||
- `src/core/command-generation/adapters/opencode.ts` (use transformer)
|
||||
- `src/core/init.ts` (pass transformer for OpenCode)
|
||||
- `src/core/update.ts` (pass transformer for OpenCode)
|
||||
- **Users**: OpenCode users will see correct `/opsx-` command references in both generated command files AND skill files
|
||||
- **Other tools**: No impact - transformation only applies to OpenCode
|
||||
@@ -0,0 +1,9 @@
|
||||
# No Spec Changes
|
||||
|
||||
This is a bug fix that doesn't modify any external requirements or contracts.
|
||||
|
||||
The proposal's Capabilities section indicates:
|
||||
- **New Capabilities**: None
|
||||
- **Modified Capabilities**: None
|
||||
|
||||
No spec files are needed for this implementation-only fix.
|
||||
@@ -0,0 +1,22 @@
|
||||
## 1. Implementation
|
||||
|
||||
- [x] 1.1 Create `src/utils/command-references.ts` with `transformToHyphenCommands()` function
|
||||
- [x] 1.2 Export `transformToHyphenCommands` from `src/utils/index.ts`
|
||||
- [x] 1.3 Update `generateSkillContent()` in `src/core/shared/skill-generation.ts` to accept optional `transformInstructions` callback
|
||||
- [x] 1.4 Update OpenCode adapter in `src/core/command-generation/adapters/opencode.ts` to use `transformToHyphenCommands()` for body text
|
||||
- [x] 1.5 Update `init.ts` to pass transformer when generating skills for OpenCode
|
||||
- [x] 1.6 Update `update.ts` to pass transformer when generating skills for OpenCode
|
||||
|
||||
## 2. Testing
|
||||
|
||||
- [x] 2.1 Create `test/utils/command-references.test.ts` with unit tests for `transformToHyphenCommands()`
|
||||
- [x] 2.2 Add test to `test/core/command-generation/adapters.test.ts` for OpenCode body transformation
|
||||
- [x] 2.3 Add test to `test/core/shared/skill-generation.test.ts` for transformer callback
|
||||
|
||||
## 3. Verification
|
||||
|
||||
- [x] 3.1 Run `npx vitest run test/utils/command-references.test.ts test/core/command-generation/adapters.test.ts test/core/shared/skill-generation.test.ts` to ensure tests pass
|
||||
- [x] 3.2 Run `pnpm run build` to ensure no TypeScript errors
|
||||
- [x] 3.3 Run `openspec init --tools opencode` in a temp directory and verify:
|
||||
- Command files in `.opencode/command/` contain `/opsx-` references (not `/opsx:`)
|
||||
- Skill files in `.opencode/skills/` contain `/opsx-` references (not `/opsx:`)
|
||||
+2
-2
@@ -18,7 +18,7 @@ Each AI tool has:
|
||||
- Create a generic, extensible command generation system
|
||||
|
||||
**Non-Goals:**
|
||||
- Global path installation (deferred to future work)
|
||||
- Global path installation for tools other than Codex (Codex uses absolute adapter paths today)
|
||||
- Multi-tool generation in single command (future enhancement)
|
||||
- Unifying with existing SlashCommandConfigurator (separate systems for now)
|
||||
|
||||
@@ -41,7 +41,7 @@ interface AIToolOption {
|
||||
**Rationale**:
|
||||
- Skills follow Agent Skills spec: `<toolDir>/skills/` - suffix is standard
|
||||
- Commands need per-tool formatting, handled by adapters (not a simple path)
|
||||
- Global paths deferred - can extend interface later
|
||||
- Global paths supported — Codex adapter returns absolute paths via os.homedir()
|
||||
|
||||
### 2. Strategy/Adapter pattern for command generation
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ The system SHALL define a `ToolCommandAdapter` interface for per-tool formatting
|
||||
- **WHEN** implementing a tool adapter
|
||||
- **THEN** `ToolCommandAdapter` SHALL require:
|
||||
- `toolId`: string identifier matching `AIToolOption.value`
|
||||
- `getFilePath(commandId: string)`: returns relative file path for command
|
||||
- `getFilePath(commandId: string)`: returns file path for command (relative from project root, or absolute for global-scoped tools like Codex)
|
||||
- `formatFile(content: CommandContent)`: returns complete file content with frontmatter
|
||||
|
||||
#### Scenario: Claude adapter formatting
|
||||
@@ -49,7 +49,7 @@ The system SHALL define a `ToolCommandAdapter` interface for per-tool formatting
|
||||
|
||||
- **WHEN** formatting a command for Windsurf
|
||||
- **THEN** the adapter SHALL output YAML frontmatter with `name`, `description`, `category`, `tags` fields
|
||||
- **AND** file path SHALL follow pattern `.windsurf/commands/opsx/<id>.md`
|
||||
- **AND** file path SHALL follow pattern `.windsurf/workflows/opsx-<id>.md`
|
||||
|
||||
### Requirement: Command generator function
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-17
|
||||
@@ -0,0 +1,288 @@
|
||||
## Context
|
||||
|
||||
OpenSpec currently installs 10 workflows (skills + commands) for every user, overwhelming new users. The init flow asks multiple questions (profile, delivery, tools) creating friction before users can experience value.
|
||||
|
||||
Current architecture:
|
||||
- `src/core/init.ts` - Handles tool selection and skill/command generation
|
||||
- `src/core/config.ts` - Defines `AI_TOOLS` with `skillsDir` mappings
|
||||
- `src/core/shared/skill-generation.ts` - Generates skill files from templates
|
||||
- `src/core/templates/workflows/*.ts` - Individual workflow templates
|
||||
- `src/prompts/searchable-multi-select.ts` - Tool selection UI
|
||||
|
||||
Global config exists at `~/.config/openspec/config.json` for telemetry/feature flags. Profile/delivery settings will extend this existing config.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Get new users to "aha moment" in under 1 minute
|
||||
- Smart defaults init with auto-detection and confirmation (core profile, both delivery)
|
||||
- Auto-detect installed tools from existing directories
|
||||
- Introduce profile system (core/custom) for workflow selection
|
||||
- Introduce delivery config (skills/commands/both) as power-user setting
|
||||
- Create new `propose` workflow combining `new` + `ff`
|
||||
- Fix tool selection UX (space to select, enter to confirm)
|
||||
- Maintain backwards compatibility for existing users
|
||||
|
||||
**Non-Goals:**
|
||||
- Removing any existing workflows (all remain available via custom profile)
|
||||
- Per-project profile/delivery settings (user-level only)
|
||||
- Changing the artifact structure or schema system
|
||||
- Modifying how skills/commands are formatted or written
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. Extend Existing Global Config
|
||||
|
||||
Add profile/delivery settings to existing `~/.config/openspec/config.json` (via `src/core/global-config.ts`).
|
||||
|
||||
**Rationale:** Global config already exists with XDG/APPDATA cross-platform path handling, schema evolution, and merge-with-defaults behavior. Reusing it avoids a second config file and leverages existing infrastructure.
|
||||
|
||||
**Schema extension:**
|
||||
```json
|
||||
{
|
||||
"telemetry": { ... }, // existing
|
||||
"featureFlags": { ... }, // existing
|
||||
"profile": "core", // NEW
|
||||
"delivery": "both", // NEW
|
||||
"workflows": [...] // NEW (only for custom profile)
|
||||
}
|
||||
```
|
||||
|
||||
**Alternatives considered:**
|
||||
- New `~/.openspec/config.yaml`: Creates second config file, different format, path confusion
|
||||
- Project config: Would require syncing mechanism, users edit it directly
|
||||
- Environment variables: Less discoverable, harder to persist
|
||||
|
||||
### 2. Profile System with Two Tiers
|
||||
|
||||
```
|
||||
core (default): propose, explore, apply, archive (4)
|
||||
custom: user-defined subset of workflows
|
||||
```
|
||||
|
||||
**Rationale:** Core covers the essential loop (propose → explore → apply → archive). Custom allows users to pick exactly what they need via an interactive picker.
|
||||
|
||||
**Configuration UX:**
|
||||
```
|
||||
$ openspec config profile
|
||||
|
||||
Delivery: [skills] [commands] [both]
|
||||
^^^^^^
|
||||
|
||||
Workflows: (space to toggle, enter to save)
|
||||
[x] propose
|
||||
[x] explore
|
||||
[x] apply
|
||||
[x] archive
|
||||
[ ] new
|
||||
[ ] ff
|
||||
...
|
||||
```
|
||||
|
||||
**Alternatives considered:**
|
||||
- Three tiers (core/extended/custom): Extended is redundant - users who want all workflows can select them in custom
|
||||
- Separate commands for profile and delivery: Combining into one picker reduces cognitive load
|
||||
|
||||
### 3. Propose Workflow = New + FF Combined
|
||||
|
||||
Single workflow that creates a change and generates all artifacts in one step.
|
||||
|
||||
**Rationale:** Most users want to go from idea to implementation-ready. Separating `new` (creates folder) and `ff` (generates artifacts) adds unnecessary steps. Power users who want control can use `new` + `continue` via custom profile.
|
||||
|
||||
**Implementation:** New template in `src/core/templates/workflows/propose.ts` that:
|
||||
1. Creates change directory via `openspec new change`
|
||||
2. Runs artifact generation loop (like ff does)
|
||||
3. Includes onboarding-style explanations in output
|
||||
|
||||
### 4. Auto-Detection with Confirmation
|
||||
|
||||
Scan for existing tool directories, pre-select detected tools, ask for confirmation.
|
||||
|
||||
**Rationale:** Reduces questions while still giving user control. Better than full auto (no confirmation) which might install unwanted tools, or no detection (always ask) which adds friction.
|
||||
|
||||
**Detection logic:**
|
||||
```typescript
|
||||
// Use existing AI_TOOLS config to get directory mappings
|
||||
// Each tool in AI_TOOLS has a skillsDir property (e.g., '.claude', '.cursor', '.windsurf')
|
||||
// Scan cwd for existing directories matching skillsDir values, pre-select matches
|
||||
const detectedTools = AI_TOOLS.filter(tool =>
|
||||
fs.existsSync(path.join(cwd, tool.skillsDir))
|
||||
);
|
||||
```
|
||||
|
||||
### 5. Delivery as Part of Profile Config
|
||||
|
||||
Delivery preference (skills/commands/both) stored in global config, defaulting to "both".
|
||||
|
||||
**Rationale:** Most users don't know or care about this distinction. Power users who have a preference can set it via `openspec config profile` interactive picker. Not worth asking during init.
|
||||
|
||||
### 6. Filesystem as Truth for Installed Workflows
|
||||
|
||||
What's installed in `.claude/skills/` (etc.) is the source of truth, not config.
|
||||
|
||||
**Rationale:**
|
||||
- Backwards compatible with existing installs
|
||||
- User can manually add/remove skill directories
|
||||
- Config profile is a "template" for what to install, not a constraint
|
||||
|
||||
**Behavior:**
|
||||
- `openspec init` sets up new projects OR re-initializes existing projects (selects tools, generates workflows)
|
||||
- `openspec update` refreshes an existing project to match current config (no tool selection)
|
||||
- `openspec config profile` updates global config only, offers to run update if in a project
|
||||
- Extra workflows (not in profile) are preserved
|
||||
- Delivery changes are applied: switching to `skills` removes commands, switching to `commands` removes skills
|
||||
|
||||
**Why not a separate tool manifest?**
|
||||
|
||||
Tool selection (which assistants a project uses) is per-user AND per-project, but the two config locations are per-user-only (global config) or per-project-shared (checked-in project config). A separate manifest was explored and rejected:
|
||||
|
||||
- *Path-keyed global config* (`projects: { "/path": { tools: [...] } }`): Fragile on directory move/rename/delete, symlink ambiguity, and project behavior depends on invisible external state.
|
||||
- *Gitignored local file* (`.openspec.local`): Lost on fresh clone, adds file management overhead.
|
||||
- *Checked-in project config* (`openspec/config.yaml` with `tools` field): Forces tool choices on the whole team — Alice uses Claude Code, Bob uses Cursor, neither wants the other's tools mandated.
|
||||
|
||||
The filesystem approach avoids all three problems. For teams, it's actually beneficial: checked-in skill files mean `openspec update` from any team member refreshes skills for all tools the project supports. The generated files serve as both the deliverable and the implicit tool manifest.
|
||||
|
||||
Known gap: a tool that stores config outside the project tree (no local directory to scan) would need tool-specific handling, since there's nothing in the project to scan. Address if/when such a tool is supported.
|
||||
|
||||
**When to use init vs update:**
|
||||
- `init`: First time setup, or when you want to change which tools are configured
|
||||
- `update`: After changing config, or to refresh templates to latest version
|
||||
|
||||
### 8. Existing User Migration
|
||||
|
||||
When `openspec init` or `openspec update` encounters a project with existing workflows but no `profile` field in global config, it performs a one-time migration to preserve the user's current setup.
|
||||
|
||||
**Rationale:** Without migration, existing users would default to `core` profile, causing `propose` to be added on top of their 10 workflows — making things worse, not better. Migration ensures existing users keep exactly what they have.
|
||||
|
||||
**Triggered by:** Both `init` (re-init on existing project) and `update`. The migration check is a shared function called early in both commands, before profile resolution.
|
||||
|
||||
**Detection logic:**
|
||||
```typescript
|
||||
// Shared migration check, called by both init and update:
|
||||
function migrateIfNeeded(projectPath: string, tools: AiTool[]): void {
|
||||
const globalConfig = readGlobalConfig();
|
||||
if (globalConfig.profile) return; // already migrated or explicitly set
|
||||
|
||||
const installedWorkflows = scanInstalledWorkflows(projectPath, tools);
|
||||
if (installedWorkflows.length === 0) return; // new user, use core defaults
|
||||
|
||||
// Existing user — migrate to custom profile
|
||||
writeGlobalConfig({
|
||||
...globalConfig,
|
||||
profile: 'custom',
|
||||
delivery: 'both',
|
||||
workflows: installedWorkflows,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**Scanning logic:**
|
||||
- Scan all tool directories (`.claude/skills/`, `.cursor/skills/`, etc.) for workflow directories/files
|
||||
- Match only against `ALL_WORKFLOWS` constant — ignore user-created custom skills/commands
|
||||
- Map directory names back to workflow IDs (e.g., `openspec-explore/` → `explore`, `opsx-explore.md` → `explore`)
|
||||
- Take the union of detected workflow names across all tools
|
||||
|
||||
**Edge cases:**
|
||||
- **User manually deleted some workflows:** Migration scans what's actually installed, respecting their choices
|
||||
- **Multiple projects with different workflow sets:** First project to trigger migration sets global config; subsequent projects use it
|
||||
- **User has custom (non-OpenSpec) skills in the directory:** Ignored — scanner only matches known workflow IDs from `ALL_WORKFLOWS`
|
||||
- **Migration is idempotent:** If `profile` is already set in config, no re-migration occurs
|
||||
- **Non-interactive (CI):** Same migration logic, no confirmation needed — it's preserving existing state
|
||||
|
||||
**Alternatives considered:**
|
||||
- Migrate during `init` instead of `update`: Init already has its own flow (tool selection, etc.). Mixing migration with init creates confusing UX
|
||||
- Don't migrate, just default to core: Breaks existing users by adding `propose` and showing "extra workflows" warnings
|
||||
- Migrate at global config read time: Too implicit, hard to show feedback to user
|
||||
|
||||
### 9. Generic Next-Step Guidance in Templates
|
||||
|
||||
Workflow templates use generic, concept-based next-step guidance rather than referencing specific workflow commands. For example, instead of "run `/opsx:propose`", templates say "create a change proposal".
|
||||
|
||||
**Rationale:** Conditional cross-referencing (where each template checks which other workflows are installed and renders different command names) adds significant complexity to template generation, testing, and maintenance. Generic guidance avoids this entirely while still being useful — users already know their installed workflows.
|
||||
|
||||
**Note:** If we find that users consistently struggle to map concepts to commands, we can revisit this with conditional cross-references. For now, simplicity wins.
|
||||
|
||||
### 7. Fix Multi-Select Keybindings
|
||||
|
||||
Change from tab-to-confirm to industry-standard space/enter.
|
||||
|
||||
**Rationale:** Tab to confirm is non-standard and confuses users. Most CLI tools use space to toggle, enter to confirm.
|
||||
|
||||
**Implementation:** Modify `src/prompts/searchable-multi-select.ts` keybinding configuration.
|
||||
|
||||
### 10. Update Sync Must Consider Config Drift, Not Just Version Drift
|
||||
|
||||
`openspec update` cannot rely only on `generatedBy` version checks for deciding whether work is needed.
|
||||
|
||||
**Rationale:** profile and delivery changes can require file add/remove operations even when existing skill templates are current. If we only check template versions, update may incorrectly return "up to date" and skip required sync.
|
||||
|
||||
**Implementation:**
|
||||
- Keep version checks for template refresh decisions
|
||||
- Add file-state drift checks for profile/delivery (missing expected files or stale files from removed delivery mode)
|
||||
- Treat either version drift OR config drift as update-required
|
||||
|
||||
### 11. Tool Configuration Detection Includes Commands-Only Installs
|
||||
|
||||
Configured-tool detection for update must include command files, not only skill files.
|
||||
|
||||
**Rationale:** with `delivery: commands`, a project can be fully configured without skill files. Skill-only detection incorrectly reports "No configured tools found."
|
||||
|
||||
**Implementation:**
|
||||
- For update flows, treat a tool as configured if it has either generated skills or generated commands
|
||||
- Keep migration workflow scanning behavior unchanged (skills remain the migration source of truth)
|
||||
|
||||
### 12. Init Profile Override Is Strictly Validated
|
||||
|
||||
`openspec init --profile` must validate allowed values before proceeding.
|
||||
|
||||
**Rationale:** silently accepting unknown profile values hides user errors and produces implicit fallback behavior.
|
||||
|
||||
**Implementation:** accept only `core` and `custom`; throw a clear CLI error for invalid values.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
**Risk: Breaking existing user workflows**
|
||||
→ Mitigation: Filesystem is truth, existing installs untouched. All workflows available via custom profile.
|
||||
|
||||
**Risk: Propose workflow duplicates ff logic**
|
||||
→ Mitigation: Extract shared artifact generation into reusable function, both `propose` and `ff` call it.
|
||||
|
||||
**Risk: Global config file management**
|
||||
→ Mitigation: Create directory/file on first use. Handle missing file gracefully (use defaults).
|
||||
|
||||
**Risk: Auto-detection false positives**
|
||||
→ Mitigation: Show detected tools and ask for confirmation, don't auto-install silently.
|
||||
|
||||
**Trade-off: Core profile has only 4 workflows**
|
||||
→ Acceptable: These cover the main loop. Users who need more can use `openspec config profile` to select additional workflows.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. **Phase 1: Add infrastructure**
|
||||
- Extend global-config.ts with profile/delivery/workflows fields
|
||||
- Profile definitions and resolution
|
||||
- Tool auto-detection
|
||||
|
||||
2. **Phase 2: Create propose workflow**
|
||||
- New template combining new + ff
|
||||
- Enhanced UX with explanatory output
|
||||
|
||||
3. **Phase 3: Update init flow**
|
||||
- Smart defaults with tool confirmation
|
||||
- Auto-detect and confirm tools
|
||||
- Respect profile/delivery settings
|
||||
|
||||
4. **Phase 4: Add config profile command**
|
||||
- `openspec config profile` interactive picker
|
||||
- `openspec config profile core` preset shortcut
|
||||
|
||||
5. **Phase 5: Update the update command**
|
||||
- Read global config for profile/delivery
|
||||
- Add missing workflows from profile
|
||||
- Delete files when delivery changes (e.g., commands removed if `skills`)
|
||||
- Display summary of changes
|
||||
|
||||
6. **Phase 6: Fix multi-select UX**
|
||||
- Update keybindings in searchable-multi-select
|
||||
|
||||
**Rollback:** All changes are additive. Existing behavior preserved via custom profile with all workflows selected.
|
||||
@@ -0,0 +1,202 @@
|
||||
## Why
|
||||
|
||||
Users have complained that there are too many skills/commands (currently 10) and new users feel overwhelmed. We want to simplify the default experience while preserving power-user capabilities and backwards compatibility.
|
||||
|
||||
The goal: **get users to an "aha moment" in under a minute**.
|
||||
|
||||
```text
|
||||
0:00 $ openspec init
|
||||
✓ Done. Run /opsx:propose "your idea"
|
||||
|
||||
0:15 /opsx:propose "add user authentication"
|
||||
|
||||
0:45 Agent creates proposal.md, design.md, tasks.md
|
||||
"Whoa, it planned the whole thing for me" ← AHA
|
||||
|
||||
1:00 /opsx:apply
|
||||
```
|
||||
|
||||
Additionally, users have different preferences for how workflows are delivered (skills vs commands vs both), but this should be a power-user configuration, not something new users think about.
|
||||
|
||||
## What Changes
|
||||
|
||||
### 1. Smart Defaults Init
|
||||
|
||||
Init auto-detects tools and asks for confirmation:
|
||||
|
||||
```text
|
||||
$ openspec init
|
||||
|
||||
Detected tools:
|
||||
[x] Claude Code
|
||||
[x] Cursor
|
||||
[ ] Windsurf
|
||||
|
||||
Press Enter to confirm, or Space to toggle
|
||||
|
||||
Setting up OpenSpec...
|
||||
✓ Done
|
||||
|
||||
Start your first change:
|
||||
/opsx:propose "add dark mode"
|
||||
```
|
||||
|
||||
**No prompts for profile or delivery.** Defaults are:
|
||||
- Profile: core
|
||||
- Delivery: both
|
||||
|
||||
Power users can customize via `openspec config profile`.
|
||||
|
||||
### 2. Tool Detection Behavior
|
||||
|
||||
Init scans for existing tool directories (`.claude/`, `.cursor/`, etc.):
|
||||
- **Tools detected (interactive):** Shows pre-selected checkboxes, user confirms or adjusts
|
||||
- **No tools detected (interactive):** Prompts for full tool selection
|
||||
- **Non-interactive (CI):** Uses detected tools automatically, fails if none detected
|
||||
|
||||
### 3. Fix Tool Selection UX
|
||||
|
||||
Current behavior confuses users:
|
||||
- Tab to confirm (unexpected)
|
||||
|
||||
New behavior:
|
||||
- **Space** to toggle selection
|
||||
- **Enter** to confirm
|
||||
|
||||
### 4. Introduce Profiles
|
||||
|
||||
Profiles define which workflows to install:
|
||||
|
||||
- **core** (default): `propose`, `explore`, `apply`, `archive` (4 workflows)
|
||||
- **custom**: User-selected subset of workflows
|
||||
|
||||
The `propose` workflow is new - it combines `new` + `ff` into a single command that creates a change and generates all artifacts.
|
||||
|
||||
### 5. Improved Propose UX
|
||||
|
||||
`/opsx:propose` should naturally onboard users by explaining what it's doing:
|
||||
|
||||
```text
|
||||
I'll create a change with 3 artifacts:
|
||||
- proposal.md (what & why)
|
||||
- design.md (how)
|
||||
- tasks.md (implementation steps)
|
||||
|
||||
When ready to implement, run /opsx:apply
|
||||
```
|
||||
|
||||
This teaches as it goes - no separate onboarding needed for most users.
|
||||
|
||||
### 6. Introduce Delivery Config
|
||||
|
||||
Delivery controls how workflows are installed:
|
||||
|
||||
- **both** (default): Skills and commands
|
||||
- **skills**: Skills only
|
||||
- **commands**: Commands only
|
||||
|
||||
Stored in existing global config (`~/.config/openspec/config.json`). Not prompted during init.
|
||||
|
||||
### 7. New CLI Commands
|
||||
|
||||
```shell
|
||||
# Profile configuration (interactive picker for delivery + workflows)
|
||||
openspec config profile # interactive picker
|
||||
openspec config profile core # preset shortcut (core workflows, preserves delivery)
|
||||
```
|
||||
|
||||
The interactive picker allows users to configure both delivery method and workflow selection in one place:
|
||||
|
||||
```
|
||||
$ openspec config profile
|
||||
|
||||
Delivery: [skills] [commands] [both]
|
||||
^^^^^^
|
||||
|
||||
Workflows: (space to toggle, enter to save)
|
||||
[x] propose
|
||||
[x] explore
|
||||
[x] apply
|
||||
[x] archive
|
||||
[ ] new
|
||||
[ ] ff
|
||||
[ ] continue
|
||||
[ ] verify
|
||||
[ ] sync
|
||||
[ ] bulk-archive
|
||||
[ ] onboard
|
||||
```
|
||||
|
||||
### 8. Backwards Compatibility & Migration
|
||||
|
||||
**Existing users keep their current setup.** When `openspec update` runs on a project with existing workflows and no `profile` in global config, it performs a one-time migration:
|
||||
|
||||
1. Scans installed workflow files across all tool directories in the project
|
||||
2. Writes `profile: "custom"`, `delivery: "both"`, `workflows: [<detected>]` to global config
|
||||
3. Refreshes templates but does NOT add or remove any workflows
|
||||
4. Displays: "Migrated: custom profile with N existing workflows"
|
||||
|
||||
After migration, subsequent `init` and `update` commands respect the migrated config.
|
||||
|
||||
**Key behaviors:**
|
||||
- Existing users' workflows are preserved exactly as-is (no `propose` added automatically)
|
||||
- Both `init` (re-init) and `update` trigger migration on existing projects if no profile is set
|
||||
- `openspec init` on a **new** project (no existing workflows) uses global config, defaulting to `core`
|
||||
- `init` with a custom profile applies the configured workflows directly (no profile confirmation prompt)
|
||||
- `init` validates `--profile` values (`core` or `custom`) and errors on invalid input
|
||||
- Migration message mentions `propose` and suggests `openspec config profile core` to opt in
|
||||
- After migration, users can opt into `core` profile via `openspec config profile core`
|
||||
- Workflow templates conditionally reference only installed workflows in "next steps" guidance
|
||||
- Delivery changes are applied: switching to `skills` removes command files, switching to `commands` removes skill files
|
||||
- Re-running `init` applies delivery cleanup on existing projects (removes files that no longer match delivery)
|
||||
- `update` treats profile/delivery drift as update-required even when template versions are already current
|
||||
- `update` treats command-only installs as configured tools
|
||||
- All workflows remain available via custom profile
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `profiles`: Workflow profiles (core, custom), delivery preferences, global config storage, interactive picker
|
||||
- `propose-workflow`: Combined workflow that creates change + generates all artifacts
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `cli-init`: Smart defaults with tool auto-detection, profile-based skill/command generation
|
||||
- `cli-update`: Profile support, delivery changes, one-time migration for existing users
|
||||
|
||||
## Impact
|
||||
|
||||
### New Files
|
||||
- `src/core/templates/workflows/propose.ts` - New propose workflow template
|
||||
- `src/core/profiles.ts` - Profile definitions and logic
|
||||
- `src/core/available-tools.ts` - Detect what AI tools user has from directories
|
||||
|
||||
### Modified Files
|
||||
- `src/core/init.ts` - Smart defaults, auto-detection, tool confirmation
|
||||
- `src/core/config.ts` - Add profile and delivery types
|
||||
- `src/core/global-config.ts` - Add profile, delivery, workflows fields to schema
|
||||
- `src/core/shared/skill-generation.ts` - Filter by profile, respect delivery
|
||||
- `src/core/shared/tool-detection.ts` - Update SKILL_NAMES and COMMAND_IDS to include propose
|
||||
- `src/commands/config.ts` - Add `profile` subcommand with interactive picker
|
||||
- `src/core/update.ts` - Add profile/delivery support, file deletion for delivery changes
|
||||
- `src/prompts/searchable-multi-select.ts` - Fix keybindings (space/enter)
|
||||
|
||||
### Global Config Schema Extension
|
||||
```json
|
||||
// ~/.config/openspec/config.json (extends existing)
|
||||
{
|
||||
"telemetry": { ... }, // existing
|
||||
"featureFlags": { ... }, // existing
|
||||
"profile": "core", // NEW: core | custom
|
||||
"delivery": "both", // NEW: both | skills | commands
|
||||
"workflows": ["propose", ...] // NEW: only if profile: custom
|
||||
}
|
||||
```
|
||||
|
||||
## Profiles Reference
|
||||
|
||||
| Profile | Workflows | Description |
|
||||
|---------|-----------|-------------|
|
||||
| core | propose, explore, apply, archive | Streamlined flow for most users (default) |
|
||||
| custom | user-defined | Pick exactly what you need via `openspec config profile` |
|
||||
@@ -0,0 +1,199 @@
|
||||
## Purpose
|
||||
|
||||
The init command SHALL provide a streamlined setup experience that auto-detects tools and uses smart defaults, getting users to their first change in under a minute.
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Skill generation per tool (REPLACES fixed 9-skill mandate)
|
||||
The init command SHALL generate skills based on the active profile, not a fixed set.
|
||||
|
||||
#### Scenario: Core profile skill generation
|
||||
- **WHEN** user runs init with profile `core`
|
||||
- **THEN** the system SHALL generate skills for workflows in CORE_WORKFLOWS constant: propose, explore, apply, archive
|
||||
- **THEN** the system SHALL NOT generate skills for workflows outside the profile
|
||||
|
||||
#### Scenario: Custom profile skill generation
|
||||
- **WHEN** user runs init with profile `custom`
|
||||
- **THEN** the system SHALL generate skills only for workflows listed in config `workflows` array
|
||||
|
||||
#### Scenario: Propose workflow included in skill templates
|
||||
- **WHEN** generating skills
|
||||
- **THEN** the system SHALL include the `propose` workflow as an available skill template
|
||||
|
||||
### Requirement: Command generation per tool (REPLACES fixed 9-command mandate)
|
||||
The init command SHALL generate commands based on profile AND delivery settings.
|
||||
|
||||
#### Scenario: Skills-only delivery
|
||||
- **WHEN** delivery is set to `skills`
|
||||
- **THEN** the system SHALL NOT generate any command files
|
||||
|
||||
#### Scenario: Commands-only delivery
|
||||
- **WHEN** delivery is set to `commands`
|
||||
- **THEN** the system SHALL NOT generate any skill files
|
||||
|
||||
#### Scenario: Both delivery
|
||||
- **WHEN** delivery is set to `both`
|
||||
- **THEN** the system SHALL generate both skill and command files for profile workflows
|
||||
|
||||
#### Scenario: Propose workflow included in command templates
|
||||
- **WHEN** generating commands
|
||||
- **THEN** the system SHALL include the `propose` workflow as an available command template
|
||||
|
||||
### Requirement: Tool auto-detection
|
||||
The init command SHALL detect installed AI tools by scanning for their configuration directories in the project root.
|
||||
|
||||
#### Scenario: Detection from directories
|
||||
- **WHEN** scanning for tools
|
||||
- **THEN** the system SHALL check for directories matching each supported AI tool's configuration directory (e.g., `.claude/`, `.cursor/`, `.windsurf/`)
|
||||
- **THEN** all tools with a matching directory SHALL be returned as detected
|
||||
|
||||
#### Scenario: Detection covers all supported tools
|
||||
- **WHEN** scanning for tools
|
||||
- **THEN** the system SHALL check for all tools defined in the supported tools configuration that have a configuration directory
|
||||
|
||||
#### Scenario: No tools detected
|
||||
- **WHEN** no tool configuration directories exist in project root
|
||||
- **THEN** the system SHALL return an empty list of detected tools
|
||||
|
||||
### Requirement: Smart defaults init flow
|
||||
The init command SHALL work with sensible defaults and tool confirmation, minimizing required user input.
|
||||
|
||||
#### Scenario: Init with detected tools (interactive)
|
||||
- **WHEN** user runs `openspec init` interactively and tool directories are detected
|
||||
- **THEN** the system SHALL show detected tools pre-selected
|
||||
- **THEN** the system SHALL ask for confirmation (not full selection)
|
||||
- **THEN** the system SHALL use default profile (`core`) and delivery (`both`)
|
||||
|
||||
#### Scenario: Init with no detected tools (interactive)
|
||||
- **WHEN** user runs `openspec init` interactively and no tool directories are detected
|
||||
- **THEN** the system SHALL prompt for tool selection
|
||||
- **THEN** the system SHALL use default profile (`core`) and delivery (`both`)
|
||||
|
||||
#### Scenario: Non-interactive with detected tools
|
||||
- **WHEN** user runs `openspec init` non-interactively (e.g., in CI)
|
||||
- **AND** tool directories are detected
|
||||
- **THEN** the system SHALL use detected tools automatically without prompting
|
||||
- **THEN** the system SHALL use default profile and delivery
|
||||
|
||||
#### Scenario: Non-interactive with no detected tools
|
||||
- **WHEN** user runs `openspec init` non-interactively
|
||||
- **AND** no tool directories are detected
|
||||
- **THEN** the system SHALL fail with exit code 1
|
||||
- **AND** display message to use `--tools` flag
|
||||
|
||||
#### Scenario: Non-interactive with explicit tools
|
||||
- **WHEN** user runs `openspec init --tools claude`
|
||||
- **THEN** the system SHALL use specified tools
|
||||
- **THEN** the system SHALL NOT prompt for any input
|
||||
|
||||
#### Scenario: Interactive with explicit tools
|
||||
- **WHEN** user runs `openspec init --tools claude` interactively
|
||||
- **THEN** the system SHALL use specified tools (ignoring auto-detection)
|
||||
- **THEN** the system SHALL NOT prompt for tool selection
|
||||
- **THEN** the system SHALL proceed with default profile and delivery
|
||||
|
||||
#### Scenario: Init success message (propose installed)
|
||||
- **WHEN** init completes successfully
|
||||
- **AND** `propose` is in the active profile
|
||||
- **THEN** the system SHALL display a tool-appropriate success message
|
||||
- **THEN** for tools using colon syntax (Claude Code): "Start your first change: /opsx:propose \"your idea\""
|
||||
- **THEN** for tools using hyphen syntax (Cursor, others): "Start your first change: /opsx-propose \"your idea\""
|
||||
|
||||
#### Scenario: Init success message (propose not installed, new installed)
|
||||
- **WHEN** init completes successfully
|
||||
- **AND** `propose` is NOT in the active profile
|
||||
- **AND** `new` is in the active profile
|
||||
- **THEN** for tools using colon syntax: "Start your first change: /opsx:new \"your idea\""
|
||||
- **THEN** for tools using hyphen syntax: "Start your first change: /opsx-new \"your idea\""
|
||||
|
||||
#### Scenario: Init success message (neither propose nor new)
|
||||
- **WHEN** init completes successfully
|
||||
- **AND** neither `propose` nor `new` is in the active profile
|
||||
- **THEN** the system SHALL display: "Done. Run 'openspec config profile' to configure your workflows."
|
||||
|
||||
### Requirement: Init performs migration on existing projects
|
||||
The init command SHALL perform one-time migration when re-initializing an existing project, using the same shared migration logic as the update command.
|
||||
|
||||
#### Scenario: Re-init on existing project (no profile set)
|
||||
- **WHEN** user runs `openspec init` on a project with existing workflow files
|
||||
- **AND** global config does not contain a `profile` field
|
||||
- **THEN** the system SHALL perform one-time migration before proceeding (see `specs/cli-update/spec.md`)
|
||||
- **THEN** the system SHALL proceed with init using the migrated config
|
||||
|
||||
#### Scenario: Init on new project (no existing workflows)
|
||||
- **WHEN** user runs `openspec init` on a project with no existing workflow files
|
||||
- **AND** global config does not contain a `profile` field
|
||||
- **THEN** the system SHALL NOT perform migration
|
||||
- **THEN** the system SHALL use `core` profile defaults
|
||||
|
||||
### Requirement: Init respects global config
|
||||
The init command SHALL read and apply settings from global config.
|
||||
|
||||
#### Scenario: User has profile preference
|
||||
- **WHEN** global config contains `profile: "custom"` with custom workflows
|
||||
- **THEN** init SHALL install custom profile workflows
|
||||
|
||||
#### Scenario: User has delivery preference
|
||||
- **WHEN** global config contains `delivery: "skills"`
|
||||
- **THEN** init SHALL install only skill files, not commands
|
||||
|
||||
#### Scenario: Override via flags
|
||||
- **WHEN** user runs `openspec init --profile core`
|
||||
- **THEN** the system SHALL use the flag value instead of config value
|
||||
- **THEN** the system SHALL NOT update the global config
|
||||
|
||||
#### Scenario: Invalid profile override
|
||||
- **WHEN** user runs `openspec init --profile <invalid>`
|
||||
- **AND** `<invalid>` is not one of `core` or `custom`
|
||||
- **THEN** the system SHALL exit with code 1
|
||||
- **THEN** the system SHALL display a validation error listing allowed profile values
|
||||
|
||||
### Requirement: Init applies configured profile without confirmation
|
||||
The init command SHALL apply the resolved profile (`--profile` override or global config) directly without prompting for confirmation.
|
||||
|
||||
#### Scenario: Init with custom profile (interactive)
|
||||
- **WHEN** user runs `openspec init` interactively
|
||||
- **AND** global config specifies `profile: "custom"` with workflows
|
||||
- **THEN** the system SHALL proceed directly using the custom profile workflows
|
||||
- **AND** the system SHALL NOT show a profile confirmation prompt
|
||||
|
||||
#### Scenario: Non-interactive init with custom profile
|
||||
- **WHEN** user runs `openspec init` non-interactively
|
||||
- **AND** global config specifies a custom profile
|
||||
- **THEN** the system SHALL proceed without confirmation
|
||||
|
||||
#### Scenario: Init with core profile
|
||||
- **WHEN** user runs `openspec init` interactively
|
||||
- **AND** profile is `core` (default)
|
||||
- **THEN** the system SHALL proceed directly without a profile confirmation prompt
|
||||
|
||||
### Requirement: Init preserves existing workflows
|
||||
The init command SHALL NOT remove workflows that are already installed, but SHALL respect delivery setting.
|
||||
|
||||
#### Scenario: Existing custom installation
|
||||
- **WHEN** user has custom profile with extra workflows and runs `openspec init` with core profile
|
||||
- **THEN** the system SHALL NOT remove extra workflows
|
||||
- **THEN** the system SHALL regenerate core workflow files, overwriting existing content with latest templates
|
||||
|
||||
#### Scenario: Init with different delivery setting
|
||||
- **WHEN** user runs `openspec init` on existing project
|
||||
- **AND** delivery setting differs from what's installed (e.g., was `both`, now `skills`)
|
||||
- **THEN** the system SHALL generate files matching current delivery setting
|
||||
- **THEN** the system SHALL delete files that don't match delivery (e.g., commands removed if `skills`)
|
||||
- **THEN** this applies to all workflows, including extras not in profile
|
||||
|
||||
#### Scenario: Re-init applies delivery cleanup even when templates are current
|
||||
- **WHEN** user runs `openspec init` on an existing project
|
||||
- **AND** existing files are already on current template versions
|
||||
- **AND** delivery changed since the previous init
|
||||
- **THEN** the system SHALL still remove files that no longer match delivery
|
||||
- **THEN** for example, switching from `both` to `skills` SHALL remove generated command files
|
||||
|
||||
### Requirement: Init tool confirmation UX
|
||||
The init command SHALL show detected tools and ask for confirmation.
|
||||
|
||||
#### Scenario: Confirmation prompt
|
||||
- **WHEN** tools are detected in interactive mode
|
||||
- **THEN** the system SHALL display: "Detected: Claude Code, Cursor"
|
||||
- **THEN** the system SHALL show pre-selected checkboxes for confirmation
|
||||
- **THEN** the system SHALL allow user to deselect unwanted tools
|
||||
@@ -0,0 +1,178 @@
|
||||
## Purpose
|
||||
|
||||
The update command SHALL apply global configuration changes to existing projects, syncing profile and delivery preferences without requiring full re-initialization.
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Update respects global profile config
|
||||
The update command SHALL read global config and apply profile settings to the project.
|
||||
|
||||
#### Scenario: Update adds missing workflows from config
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** global config specifies workflows not currently installed in the project
|
||||
- **THEN** the system SHALL generate skill/command files for missing workflows
|
||||
- **THEN** the system SHALL display: "Added: <workflow-names>"
|
||||
|
||||
#### Scenario: Update refreshes existing workflows
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** workflows are already installed in the project
|
||||
- **THEN** the system SHALL refresh those workflow files with latest templates
|
||||
- **THEN** the system SHALL display: "Updated: <workflow-names>"
|
||||
|
||||
#### Scenario: Update with no changes needed
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** installed workflows match global config
|
||||
- **AND** all templates are current
|
||||
- **AND** delivery setting matches installed files
|
||||
- **THEN** the system SHALL display: "Already up to date."
|
||||
|
||||
#### Scenario: Profile or delivery drift with current templates
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** workflow templates are current for the installed skills
|
||||
- **AND** project files do not match current profile and/or delivery config
|
||||
- **THEN** the system SHALL treat this as an update-required state (not "Already up to date.")
|
||||
- **THEN** the system SHALL add/remove files to match current profile and delivery settings
|
||||
|
||||
#### Scenario: Update summary output
|
||||
- **WHEN** update completes with changes
|
||||
- **THEN** the system SHALL display a summary:
|
||||
- "Added: propose, explore" (new workflows installed)
|
||||
- "Updated: apply, archive" (existing workflows refreshed)
|
||||
- "Removed: 4 command files" (if delivery changed)
|
||||
- **THEN** the system SHALL list affected tools: "Tools: Claude Code, Cursor"
|
||||
|
||||
### Requirement: Update respects delivery setting
|
||||
The update command SHALL add or remove files based on the delivery setting.
|
||||
|
||||
#### Scenario: Delivery changed to skills-only
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** global config specifies `delivery: skills`
|
||||
- **AND** project has command files installed
|
||||
- **THEN** the system SHALL delete command files for workflows in the profile
|
||||
- **THEN** the system SHALL generate/update skill files only
|
||||
- **THEN** the system SHALL display: "Removed: <count> command files (delivery: skills)"
|
||||
|
||||
#### Scenario: Delivery changed to commands-only
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** global config specifies `delivery: commands`
|
||||
- **AND** project has skill files installed
|
||||
- **THEN** the system SHALL delete skill directories for workflows in the profile
|
||||
- **THEN** the system SHALL generate/update command files only
|
||||
- **THEN** the system SHALL display: "Removed: <count> skill directories (delivery: commands)"
|
||||
|
||||
#### Scenario: Delivery is both
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** global config specifies `delivery: both`
|
||||
- **THEN** the system SHALL generate/update both skill and command files
|
||||
|
||||
### Requirement: Update detects configured tools from skills or commands
|
||||
The update command SHALL treat a tool as configured if it has either generated skill files or generated command files.
|
||||
|
||||
#### Scenario: Commands-only installation
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** a tool has generated OpenSpec command files
|
||||
- **AND** that tool has no OpenSpec skill files (commands-only delivery)
|
||||
- **THEN** the tool SHALL still be treated as configured
|
||||
- **THEN** the system SHALL apply profile and delivery sync for that tool
|
||||
|
||||
### Requirement: One-time migration for existing users
|
||||
The update command SHALL detect existing users (no `profile` in global config + existing workflows) and migrate them to `custom` profile before applying updates.
|
||||
|
||||
#### Scenario: First update after upgrade (existing user)
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** global config does not contain a `profile` field
|
||||
- **AND** project has existing workflow files installed
|
||||
- **THEN** the system SHALL scan installed workflows across all tool directories in the project
|
||||
- **THEN** the system SHALL only match workflow names present in `ALL_WORKFLOWS` constant (ignoring user-created custom skills)
|
||||
- **THEN** the system SHALL take the union of detected workflow names across all tools
|
||||
- **THEN** the system SHALL write to global config: `profile: "custom"`, `delivery: "both"`, `workflows: [<detected>]`
|
||||
- **THEN** the system SHALL display: "Migrated: custom profile with <count> workflows (<workflow-names>)"
|
||||
- **THEN** the system SHALL display: "New in this version: /opsx:propose (combines new + ff). Try 'openspec config profile core' for the streamlined 4-workflow experience."
|
||||
- **THEN** the system SHALL proceed with normal update logic (using the migrated config)
|
||||
- **THEN** the result SHALL be template refresh only (no workflows added or removed)
|
||||
|
||||
#### Scenario: Migration with partial workflows (user manually removed some)
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** global config does not contain a `profile` field
|
||||
- **AND** project has fewer than the original 10 workflows installed
|
||||
- **THEN** the system SHALL migrate with only the workflows that are actually present
|
||||
- **THEN** the migrated `workflows` array SHALL reflect the user's current state, not the original set
|
||||
|
||||
#### Scenario: Migration with multiple tools having different workflow sets
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** project has multiple tools configured (e.g., Claude Code, Cursor)
|
||||
- **AND** different tools have different workflows installed
|
||||
- **THEN** the system SHALL take the union of all detected workflows across all tools
|
||||
- **THEN** the migrated `workflows` array SHALL include any workflow that exists in at least one tool
|
||||
|
||||
#### Scenario: No migration needed (profile already set)
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** global config already contains a `profile` field
|
||||
- **THEN** the system SHALL NOT perform migration
|
||||
- **THEN** the system SHALL proceed with normal update logic using existing config
|
||||
|
||||
#### Scenario: No migration needed (no existing workflows)
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** global config does not contain a `profile` field
|
||||
- **AND** project has no existing workflow files
|
||||
- **THEN** the system SHALL NOT perform migration
|
||||
- **THEN** the system SHALL use `core` profile defaults
|
||||
|
||||
#### Scenario: Migration is idempotent
|
||||
- **WHEN** user runs `openspec update` multiple times
|
||||
- **THEN** migration SHALL only occur on the first run (when `profile` field is absent)
|
||||
- **THEN** subsequent runs SHALL use the existing global config without re-scanning
|
||||
|
||||
#### Scenario: Non-interactive migration
|
||||
- **WHEN** user runs `openspec update` non-interactively (e.g., in CI)
|
||||
- **AND** migration is triggered
|
||||
- **THEN** the system SHALL perform migration without prompting
|
||||
- **THEN** the system SHALL display the migration summary to stdout
|
||||
|
||||
### Requirement: Update detects new tool directories
|
||||
The update command SHALL notify the user if new AI tool directories are detected that aren't currently configured.
|
||||
|
||||
#### Scenario: New tool directory detected
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** a new tool directory is detected (e.g., `.windsurf/` exists but Windsurf is not configured)
|
||||
- **THEN** the system SHALL display: "Detected new tool: Windsurf. Run 'openspec init' to add it."
|
||||
- **THEN** the system SHALL NOT automatically add the new tool
|
||||
- **THEN** the system SHALL proceed with update for currently configured tools only
|
||||
|
||||
#### Scenario: Multiple new tool directories detected
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** multiple new tool directories are detected (e.g., `.github/` and `.windsurf/` exist but neither tool is configured)
|
||||
- **THEN** the system SHALL display one consolidated message listing all detected tools, for example: "Detected new tools: GitHub Copilot, Windsurf. Run 'openspec init' to add them."
|
||||
- **THEN** the system SHALL NOT automatically add any new tools
|
||||
- **THEN** the system SHALL proceed with update for currently configured tools only
|
||||
|
||||
#### Scenario: No new tool directories
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** no new tool directories are detected
|
||||
- **THEN** the system SHALL NOT display any tool detection message
|
||||
|
||||
### Requirement: Update requires an OpenSpec project
|
||||
The update command SHALL only run inside an initialized OpenSpec project.
|
||||
|
||||
#### Scenario: Update outside a project
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** no `openspec/` directory exists in the current working directory
|
||||
- **THEN** the system SHALL display: "No OpenSpec project found. Run 'openspec init' to set up."
|
||||
- **THEN** the system SHALL exit with code 1
|
||||
|
||||
### Requirement: Extra workflows preserved
|
||||
The update command SHALL NOT remove workflow files that aren't in the current profile.
|
||||
|
||||
#### Scenario: Extra workflows from previous profile
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** project has workflows not in current profile (e.g., user switched from custom to core)
|
||||
- **THEN** the system SHALL NOT delete those extra workflow files
|
||||
- **THEN** the system SHALL only add/update workflows in the current profile
|
||||
- **THEN** the system SHALL display a note: "Note: <count> extra workflows not in profile (use `openspec config profile` to manage)"
|
||||
|
||||
#### Scenario: Delivery change with extra workflows
|
||||
- **WHEN** user runs `openspec update`
|
||||
- **AND** delivery changed (e.g., `both` → `skills`)
|
||||
- **AND** project has extra workflows not in current profile
|
||||
- **THEN** the system SHALL delete files for extra workflows that match the removed delivery type
|
||||
- **THEN** for example: if switching to `skills`, all command files are deleted (including for extra workflows)
|
||||
@@ -0,0 +1,142 @@
|
||||
## Purpose
|
||||
|
||||
Profiles SHALL define which workflows to install, enabling a streamlined core experience for new users while allowing power users to customize their workflow selection.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Profile definitions
|
||||
The system SHALL support two workflow profiles: `core` and `custom`.
|
||||
|
||||
#### Scenario: Core profile contents
|
||||
- **WHEN** profile is set to `core`
|
||||
- **THEN** the profile SHALL include workflows: `propose`, `explore`, `apply`, `archive`
|
||||
|
||||
#### Scenario: Custom profile contents
|
||||
- **WHEN** profile is set to `custom`
|
||||
- **THEN** the profile SHALL include only the workflows specified in global config `workflows` array
|
||||
|
||||
### Requirement: Delivery is independent of profile
|
||||
The delivery setting SHALL control HOW workflows are installed (skills, commands, or both), separate from WHICH workflows are installed.
|
||||
|
||||
#### Scenario: Delivery options
|
||||
- **WHEN** configuring delivery
|
||||
- **THEN** the system SHALL support three options: `both` (skills and commands), `skills` (skill files only), `commands` (command files only)
|
||||
|
||||
#### Scenario: Both delivery
|
||||
- **WHEN** delivery is set to `both`
|
||||
- **THEN** the system SHALL install both skill files and command files for each workflow
|
||||
|
||||
#### Scenario: Skills-only delivery
|
||||
- **WHEN** delivery is set to `skills`
|
||||
- **THEN** the system SHALL install only skill files for each workflow
|
||||
- **THEN** the system SHALL NOT install command files
|
||||
|
||||
#### Scenario: Commands-only delivery
|
||||
- **WHEN** delivery is set to `commands`
|
||||
- **THEN** the system SHALL install only command files for each workflow
|
||||
- **THEN** the system SHALL NOT install skill files
|
||||
|
||||
#### Scenario: Core profile with custom delivery
|
||||
- **WHEN** profile is set to `core`
|
||||
- **AND** delivery is set to `skills`
|
||||
- **THEN** the system SHALL install core workflows as skills only (no commands)
|
||||
|
||||
#### Scenario: Delivery defaults
|
||||
- **WHEN** delivery is not set in global config
|
||||
- **THEN** the system SHALL default to `both`
|
||||
|
||||
### Requirement: Profile configuration via interactive picker
|
||||
The system SHALL provide an interactive picker for configuring profiles.
|
||||
|
||||
#### Scenario: Interactive profile configuration
|
||||
- **WHEN** user runs `openspec config profile`
|
||||
- **THEN** the system SHALL display an interactive picker with:
|
||||
- Delivery selection: `skills`, `commands`, `both`
|
||||
- Workflow toggles for all available workflows
|
||||
- **THEN** the system SHALL pre-select current config values
|
||||
- **THEN** on confirmation, the system SHALL update global config
|
||||
- **THEN** the system SHALL set profile to `custom` if selected workflows differ from core defaults
|
||||
- **THEN** the system SHALL set profile to `core` if selected workflows match core defaults exactly (propose, explore, apply, archive), regardless of delivery setting
|
||||
- **THEN** the system SHALL NOT modify any project files
|
||||
- **THEN** the system SHALL display: "Config updated. Run `openspec update` in your projects to apply."
|
||||
|
||||
#### Scenario: Core preset shortcut
|
||||
- **WHEN** user runs `openspec config profile core`
|
||||
- **THEN** the system SHALL set profile to `core`
|
||||
- **THEN** the system SHALL set workflows to `['propose', 'explore', 'apply', 'archive']`
|
||||
- **THEN** the system SHALL NOT change the delivery setting (preserves user preference)
|
||||
- **THEN** the system SHALL NOT modify any project files
|
||||
- **THEN** the system SHALL display: "Config updated. Run `openspec update` in your projects to apply."
|
||||
- **THEN** the new profile takes effect on the next `openspec init` or `openspec update` run
|
||||
|
||||
#### Scenario: Config profile run inside a project
|
||||
- **WHEN** user runs `openspec config profile` inside an OpenSpec project directory
|
||||
- **THEN** after updating global config, the system SHALL prompt: "Apply to this project now? (y/n)"
|
||||
- **WHEN** user confirms
|
||||
- **THEN** the system SHALL run `openspec update` automatically
|
||||
- **THEN** the system SHALL still display: "Run `openspec update` in your other projects to apply."
|
||||
|
||||
#### Scenario: Config profile - user declines apply
|
||||
- **WHEN** user runs `openspec config profile` inside an OpenSpec project directory
|
||||
- **AND** user declines the "Apply to this project now?" prompt
|
||||
- **THEN** the system SHALL display: "Config updated. Run `openspec update` in your projects to apply."
|
||||
- **THEN** the system SHALL exit successfully without modifying project files
|
||||
|
||||
#### Scenario: Config profile non-interactive
|
||||
- **WHEN** user runs `openspec config profile` non-interactively (e.g., in CI, no TTY)
|
||||
- **THEN** the system SHALL display an error: "Interactive mode required. Use `openspec config profile core` or set config via environment/flags."
|
||||
- **THEN** the system SHALL exit with code 1
|
||||
|
||||
### Requirement: Profile settings stored in global config
|
||||
Profile and delivery settings SHALL be stored in the existing global config file (`~/.config/openspec/config.json`) alongside telemetry and feature flags.
|
||||
|
||||
#### Scenario: Config schema
|
||||
- **WHEN** reading profile configuration
|
||||
- **THEN** the config SHALL contain `profile` (core|custom), `delivery` (both|skills|commands), and optionally `workflows` (array of workflow names)
|
||||
|
||||
#### Scenario: Schema evolution
|
||||
- **WHEN** loading config without profile/delivery fields
|
||||
- **THEN** the system SHALL use defaults (profile=core, delivery=both)
|
||||
- **AND** existing config fields (telemetry, featureFlags) SHALL be preserved
|
||||
|
||||
#### Scenario: Config list displays profile settings
|
||||
- **WHEN** user runs `openspec config list`
|
||||
- **THEN** the system SHALL display profile, delivery, and workflows settings
|
||||
- **AND** SHALL indicate which values are defaults vs explicitly set
|
||||
|
||||
### Requirement: Config is global, projects are explicit
|
||||
Config changes SHALL NOT automatically propagate to projects.
|
||||
|
||||
#### Scenario: Config update does not modify projects
|
||||
- **WHEN** user updates config via `openspec config profile`
|
||||
- **THEN** the system SHALL only update global config (`~/.config/openspec/config.json`)
|
||||
- **THEN** the system SHALL NOT modify any project skill/command files
|
||||
- **THEN** existing projects retain their current workflow files until user runs `openspec update`
|
||||
|
||||
### Requirement: Config changes applied via update command
|
||||
The existing `openspec update` command SHALL apply the current global config to a project. See `specs/cli-update/spec.md` for detailed update behavior.
|
||||
|
||||
#### Scenario: Config changes require explicit project sync
|
||||
- **WHEN** user updates profile or delivery via `openspec config profile`
|
||||
- **THEN** the global config SHALL be updated immediately
|
||||
- **AND** project files SHALL remain unchanged until `openspec update` is run for that project
|
||||
|
||||
### Requirement: Profile defaults
|
||||
The system SHALL use `core` as the default profile for new users, while preserving existing users' workflows via migration.
|
||||
|
||||
#### Scenario: No global config exists (new user)
|
||||
- **WHEN** global config file does not exist
|
||||
- **AND** no existing workflows are installed in the project
|
||||
- **THEN** the system SHALL behave as if profile is `core`
|
||||
|
||||
#### Scenario: Global config exists but profile field absent (new user)
|
||||
- **WHEN** global config file exists but does not contain a `profile` field
|
||||
- **AND** no existing workflows are installed in the project
|
||||
- **THEN** the system SHALL behave as if profile is `core`
|
||||
|
||||
#### Scenario: Profile field absent with existing workflows (existing user migration)
|
||||
- **WHEN** global config does not contain a `profile` field
|
||||
- **AND** the `update` command detects existing workflow files in the project
|
||||
- **THEN** the system SHALL perform one-time migration (see `specs/cli-update/spec.md` for details)
|
||||
- **THEN** the system SHALL set profile to `custom` with the detected workflows
|
||||
- **THEN** the system SHALL NOT add or remove any workflow files during migration
|
||||
@@ -0,0 +1,42 @@
|
||||
## Purpose
|
||||
|
||||
The propose workflow SHALL combine change creation and artifact generation into a single command, reducing friction for new users while teaching them the OpenSpec workflow through embedded guidance.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Propose workflow creation
|
||||
The system SHALL provide a `propose` workflow that creates a change and generates all artifacts in one step.
|
||||
|
||||
#### Scenario: Basic propose invocation
|
||||
- **WHEN** user invokes `/opsx:propose "add user authentication"`
|
||||
- **THEN** the system SHALL create a change directory with kebab-case name
|
||||
- **THEN** the system SHALL create `.openspec.yaml` in the change directory (via `openspec new change`)
|
||||
- **THEN** the system SHALL generate all artifacts needed for implementation: proposal.md, design.md, specs/, tasks.md
|
||||
|
||||
#### Scenario: Propose with existing change name
|
||||
- **WHEN** user invokes `/opsx:propose` with a name that already exists
|
||||
- **THEN** the system SHALL ask if user wants to continue existing change or create new
|
||||
- **THEN** if "continue": the system SHALL resume artifact generation from last completed state
|
||||
- **THEN** if "create new": the system SHALL prompt for a new name
|
||||
- **THEN** in non-interactive mode: the system SHALL fail with error suggesting to use a different name
|
||||
|
||||
### Requirement: Propose workflow onboarding UX
|
||||
The `propose` workflow SHALL include explanatory output to help new users understand the process.
|
||||
|
||||
#### Scenario: First-time user guidance
|
||||
- **WHEN** user invokes `/opsx:propose`
|
||||
- **THEN** the system SHALL explain what artifacts will be created (proposal.md, design.md, specs/, tasks.md)
|
||||
- **THEN** the system SHALL indicate next step (`/opsx:apply` to implement)
|
||||
|
||||
#### Scenario: Artifact creation progress
|
||||
- **WHEN** the system creates each artifact
|
||||
- **THEN** the system SHALL show progress (e.g., "✓ Created proposal.md")
|
||||
|
||||
### Requirement: Propose workflow combines new and ff
|
||||
The `propose` workflow SHALL perform the same operations as running `new` followed by `ff`.
|
||||
|
||||
#### Scenario: Equivalent to new + ff
|
||||
- **WHEN** user invokes `/opsx:propose "feature name"`
|
||||
- **THEN** the result SHALL be functionally equivalent to invoking `/opsx:new "feature-name"` followed by `/opsx:ff feature-name`
|
||||
- **THEN** the same directory structure and artifacts SHALL be created
|
||||
- **THEN** console output MAY differ (propose includes onboarding explanations)
|
||||
@@ -0,0 +1,132 @@
|
||||
## 1. Global Config Extension
|
||||
|
||||
- [x] 1.1 Extend `src/core/global-config.ts` schema with `profile`, `delivery`, and `workflows` fields
|
||||
- [x] 1.2 Add TypeScript types for profile (`core` | `custom`), delivery (`both` | `skills` | `commands`), and workflows (string array)
|
||||
- [x] 1.3 Update `GlobalConfig` interface and defaults (profile=`core`, delivery=`both`)
|
||||
- [x] 1.4 Update existing `readGlobalConfig()` to handle missing new fields with defaults
|
||||
- [x] 1.5 Add tests for schema evolution (existing config without new fields)
|
||||
|
||||
## 2. Profile System
|
||||
|
||||
- [x] 2.1 Create `src/core/profiles.ts` with profile definitions (core, custom)
|
||||
- [x] 2.2 Define `CORE_WORKFLOWS` constant: `['propose', 'explore', 'apply', 'archive']`
|
||||
- [x] 2.3 Define `ALL_WORKFLOWS` constant with all 11 workflows
|
||||
- [x] 2.4 Add `COMMAND_IDS` constant to `src/core/shared/tool-detection.ts` (parallel to existing SKILL_NAMES)
|
||||
- [x] 2.5 Implement `getProfileWorkflows(profile, customWorkflows?)` resolver function
|
||||
- [x] 2.6 Add tests for profile resolution
|
||||
|
||||
## 3. Config Profile Command (Interactive Picker)
|
||||
|
||||
- [x] 3.1 Add `config profile` subcommand to `src/commands/config.ts`
|
||||
- [x] 3.2 Implement interactive picker UI with delivery selection (skills/commands/both)
|
||||
- [x] 3.3 Implement interactive picker UI with workflow toggles
|
||||
- [x] 3.4 Pre-select current config values in picker
|
||||
- [x] 3.5 Update global config on confirmation (config-only, no file regeneration)
|
||||
- [x] 3.6 Display post-update message: "Config updated. Run `openspec update` in your projects to apply."
|
||||
- [x] 3.7 Detect if running inside an OpenSpec project and offer to run update automatically
|
||||
- [x] 3.8 Implement `config profile core` preset shortcut (preserves delivery setting)
|
||||
- [x] 3.9 Handle non-interactive mode: error with helpful message
|
||||
- [x] 3.10 Update `openspec config list` to display profile, delivery, and workflows settings (indicate defaults vs explicit)
|
||||
- [x] 3.11 Add tests for config profile command and config list output
|
||||
|
||||
## 4. Available Tools Detection
|
||||
|
||||
- [x] 4.1 Create `src/core/available-tools.ts` (separate from existing `tool-detection.ts`)
|
||||
- [x] 4.2 Implement `getAvailableTools(projectPath)` that scans for AI tool directories (`.claude/`, `.cursor/`, etc.)
|
||||
- [x] 4.3 Use `AI_TOOLS` config to map directory names to tool IDs
|
||||
- [x] 4.4 Add tests for available tools detection including cross-platform paths
|
||||
|
||||
## 5. Propose Workflow Template
|
||||
|
||||
- [x] 5.1 Create `src/core/templates/workflows/propose.ts`
|
||||
- [x] 5.2 Implement skill template that combines new + ff behavior
|
||||
- [x] 5.3 Ensure propose creates `.openspec.yaml` via `openspec new change` before generating artifacts
|
||||
- [x] 5.4 Add onboarding-style explanatory output to template
|
||||
- [x] 5.5 Implement command template for propose
|
||||
- [x] 5.6 Export templates from `src/core/templates/skill-templates.ts`
|
||||
- [x] 5.7 Add `openspec-propose` to `SKILL_NAMES` in `src/core/shared/tool-detection.ts`
|
||||
- [x] 5.8 Add `propose` to command templates in `src/core/shared/skill-generation.ts`
|
||||
- [x] 5.9 Add `propose` to `COMMAND_IDS` in `src/core/shared/tool-detection.ts`
|
||||
- [x] 5.10 Add tests for propose template (creates change, generates artifacts, equivalent to new + ff)
|
||||
|
||||
## 6. Conditional Skill/Command Generation
|
||||
|
||||
- [x] 6.1 Update `getSkillTemplates()` to accept profile filter parameter
|
||||
- [x] 6.2 Update `getCommandTemplates()` to accept profile filter parameter
|
||||
- [x] 6.3 Update `generateSkillsAndCommands()` in init.ts to respect delivery setting
|
||||
- [x] 6.4 Add logic to skip skill generation when delivery is 'commands'
|
||||
- [x] 6.5 Add logic to skip command generation when delivery is 'skills'
|
||||
- [x] 6.6 Add tests for conditional generation
|
||||
|
||||
## 7. Init Flow Updates
|
||||
|
||||
- [x] 7.1 Update init to call `getAvailableTools()` first
|
||||
- [x] 7.2 Update init to read global config for profile/delivery defaults
|
||||
- [x] 7.3 Add migration check to init: call shared `migrateIfNeeded()` before profile resolution
|
||||
- [x] 7.4 Change tool selection to show pre-selected detected tools
|
||||
- [x] 7.5 Apply configured profile directly in init (no profile confirmation prompt)
|
||||
- [x] 7.6 Update success message to show `/opsx:propose` prompt (only if propose is in the active profile)
|
||||
- [x] 7.7 Add `--profile` flag to override global config
|
||||
- [x] 7.8 Update non-interactive mode to use defaults without prompting
|
||||
- [x] 7.9 Add tests for init flow with various scenarios (including migration on re-init and custom profile behavior)
|
||||
|
||||
## 8. Update Command (Profile Support + Migration)
|
||||
|
||||
- [x] 8.1 Modify existing `src/commands/update.ts` to read global config for profile/delivery/workflows
|
||||
- [x] 8.2 Implement shared `scanInstalledWorkflows(projectPath, tools)` — scan tool directories, match only against `ALL_WORKFLOWS` constant, return union across tools
|
||||
- [x] 8.3 Implement shared `migrateIfNeeded(projectPath, tools)` — one-time migration logic used by both `init` and `update`
|
||||
- [x] 8.4 Display migration message: "Migrated: custom profile with N workflows" + "New in this version: /opsx:propose. Try 'openspec config profile core' for the streamlined experience."
|
||||
- [x] 8.5 Add project check: exit with error if no `openspec/` directory exists
|
||||
- [x] 8.6 Add logic to detect which workflows are in config but not installed (to add)
|
||||
- [x] 8.7 Add logic to detect which workflows are installed and need refresh (to update)
|
||||
- [x] 8.8 Respect delivery setting: generate only skills if `skills`, only commands if `commands`
|
||||
- [x] 8.9 Delete files when delivery changes: remove commands if `skills`, remove skills if `commands`
|
||||
- [x] 8.10 Generate new workflow files for missing workflows in profile
|
||||
- [x] 8.11 Display summary: "Added: X, Y" / "Updated: Z" / "Removed: N files" / "Already up to date."
|
||||
- [x] 8.12 List affected tools in output: "Tools: Claude Code, Cursor"
|
||||
- [x] 8.13 Detect new tool directories not currently configured and display hint to re-init
|
||||
- [x] 8.14 Add tests for migration scenarios (existing user, partial workflows, multiple tools, idempotent, custom skills ignored)
|
||||
- [x] 8.15 Add tests for update command with profile scenarios (including delivery changes, outside-project error, new tool detection)
|
||||
|
||||
## 9. Tool Selection UX Fix
|
||||
|
||||
- [x] 9.1 Update `src/prompts/searchable-multi-select.ts` keybindings
|
||||
- [x] 9.2 Change Space to toggle selection
|
||||
- [x] 9.3 Change Enter to confirm selection
|
||||
- [x] 9.4 Remove Tab-to-confirm behavior
|
||||
- [x] 9.5 Add hint text "Space to toggle, Enter to confirm"
|
||||
- [x] 9.6 Add tests for keybinding behavior
|
||||
|
||||
## 10. Scaffolding Verification
|
||||
|
||||
- [x] 10.1 Verify `openspec new change` creates `.openspec.yaml` with schema and created fields
|
||||
|
||||
<!-- Note: 10.2 and 10.3 below are potential follow-up work, not core to this change -->
|
||||
<!-- - [ ] 10.2 Update ff skill to verify `.openspec.yaml` exists after `openspec new change` -->
|
||||
<!-- - [ ] 10.3 Add guardrail to skills: "Never manually create files in openspec/changes/ - use openspec new change" -->
|
||||
|
||||
## 11. Template Next-Step Guidance
|
||||
|
||||
- [x] 11.1 Audit all templates for hardcoded cross-workflow command references (e.g., `/opsx:propose`)
|
||||
- [x] 11.2 Replace any specific command references with generic concept-based guidance (e.g., "create a change proposal")
|
||||
- [x] 11.3 Review explore → propose transition UX (see `openspec/explorations/explore-workflow-ux.md` for open questions)
|
||||
|
||||
## 12. Integration & Manual Testing
|
||||
|
||||
- [x] 12.1 Run full test suite and fix any failures
|
||||
- [x] 12.2 Test on Windows (or verify CI passes on Windows)
|
||||
- [x] 12.3 Test end-to-end flow: init → propose → apply → archive
|
||||
- [x] 12.4 Update CLI help text for new commands
|
||||
- [x] 12.5 Manual: interactive init — verify detected tools are pre-selected, confirm prompt works, success message is correct
|
||||
- [x] 12.6 Manual: `openspec config profile` picker — verify delivery toggle, workflow toggles, pre-selection of current values, core preset shortcut
|
||||
- [x] 12.7 Manual: init with custom profile — verify init proceeds without profile confirmation prompt
|
||||
- [x] 12.8 Manual: delivery change via update — verify correct files are deleted/created when switching between skills/commands/both
|
||||
- [x] 12.9 Manual: migration flow — run update on a pre-existing project with no profile in config, verify migration message and resulting config
|
||||
|
||||
## 13. Post-Implementation Hardening (Review Follow-up)
|
||||
|
||||
- [x] 13.1 Ensure `update` treats profile/delivery drift as update-required even when templates are current
|
||||
- [x] 13.2 Ensure `update` recognizes command-only installations as configured tools
|
||||
- [x] 13.3 Ensure `init` validates `--profile` values and errors on invalid overrides
|
||||
- [x] 13.4 Ensure re-running `init` applies delivery cleanup (removes files not matching current delivery mode)
|
||||
- [x] 13.5 Add/adjust regression tests for config drift sync, command-only detection, invalid profile override, and re-init delivery cleanup
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-16
|
||||
@@ -0,0 +1,187 @@
|
||||
## Context
|
||||
|
||||
OpenSpec currently has strong building blocks (workflow templates, command adapters, generation helpers), but orchestration concerns are distributed:
|
||||
|
||||
- Workflow definitions and projection lists are maintained separately
|
||||
- Tool support is represented in multiple places with partial overlap
|
||||
- Transforms can happen at template rendering time and inside individual adapters
|
||||
- `init`/`update`/legacy-upgrade each run similar write pipelines with slight differences
|
||||
|
||||
The design goal is to preserve current behavior while making extension points explicit and deterministic.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Define one canonical source for workflow content and metadata
|
||||
- Make tool/agent-specific behavior explicit and centrally discoverable
|
||||
- Keep command adapters as the formatting boundary for tool syntax differences
|
||||
- Represent tool-specific command surfaces and terminology explicitly (not as scattered string rewrites)
|
||||
- Consolidate artifact generation/write orchestration into one reusable engine
|
||||
- Improve correctness with enforceable validation and parity tests
|
||||
|
||||
**Non-Goals:**
|
||||
- Redesigning command semantics or workflow instruction content
|
||||
- Changing user-facing CLI command names/flags in this proposal
|
||||
- Guaranteeing fully accurate literal slash-command strings for every supported tool on day one
|
||||
- Merging unrelated legacy cleanup behavior beyond artifact generation reuse
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. Canonical `WorkflowManifest`
|
||||
|
||||
**Decision**: Represent each workflow once in a manifest entry containing canonical skill and command definitions plus metadata defaults. Canonical text uses semantic tokens for tool-specific references.
|
||||
|
||||
Suggested shape:
|
||||
|
||||
```ts
|
||||
interface WorkflowManifestEntry {
|
||||
workflowId: string; // e.g. 'explore', 'ff', 'onboard'
|
||||
skillDirName: string; // e.g. 'openspec-explore'
|
||||
skill: SkillTemplate;
|
||||
command?: CommandTemplate;
|
||||
commandId?: string;
|
||||
tags: string[];
|
||||
compatibility: string;
|
||||
}
|
||||
|
||||
// Examples in canonical workflow text:
|
||||
// - {{cmd.apply}}
|
||||
// - {{cmd.continue.withArg}}
|
||||
// - {{term.change}}
|
||||
// - {{term.workflow}}
|
||||
```
|
||||
|
||||
**Rationale**:
|
||||
- Eliminates drift between multiple hand-maintained arrays
|
||||
- Makes workflow completeness testable in one place
|
||||
- Keeps split workflow modules while centralizing registration
|
||||
|
||||
### 2. `ToolProfileRegistry` for capability wiring
|
||||
|
||||
**Decision**: Add a tool profile layer that maps tool IDs to generation capabilities, command-surface rendering, and terminology.
|
||||
|
||||
Suggested shape:
|
||||
|
||||
```ts
|
||||
interface ToolProfile {
|
||||
toolId: string;
|
||||
skillsDir?: string;
|
||||
commandAdapterId?: string;
|
||||
commandSurface: {
|
||||
pattern: 'opsx-colon' | 'opsx-hyphen' | 'opsx-slash' | 'openspec-hyphen' | 'custom';
|
||||
verified: boolean;
|
||||
aliases?: string[];
|
||||
};
|
||||
terminology: {
|
||||
change: string;
|
||||
workflow: string;
|
||||
command: string;
|
||||
};
|
||||
transforms: string[];
|
||||
}
|
||||
```
|
||||
|
||||
**Rationale**:
|
||||
- Prevents capability drift between `AI_TOOLS`, adapter registry, and detection logic
|
||||
- Allows intentional "skills-only" tools without implicit special casing
|
||||
- Provides one place to answer "what does this tool support?"
|
||||
- Makes command rendering decisions explicit and testable
|
||||
- Supports future terminology tailoring without copy/paste template forks
|
||||
|
||||
### 3. First-class transform pipeline
|
||||
|
||||
**Decision**: Model transforms as ordered plugins with scope + phase + applicability. Include token rendering in the transform pipeline instead of hardcoding literal command strings in templates.
|
||||
|
||||
Suggested shape:
|
||||
|
||||
```ts
|
||||
interface ArtifactTransform {
|
||||
id: string;
|
||||
scope: 'skill' | 'command' | 'both';
|
||||
phase: 'preAdapter' | 'postAdapter';
|
||||
priority: number;
|
||||
applies(ctx: GenerationContext): boolean;
|
||||
transform(content: string, ctx: GenerationContext): string;
|
||||
}
|
||||
```
|
||||
|
||||
Execution order:
|
||||
1. Render canonical content from manifest
|
||||
2. Apply token-render transform (`{{cmd.*}}`, `{{term.*}}`) using tool profile
|
||||
3. Apply matching `preAdapter` transforms
|
||||
4. For commands, run adapter formatting
|
||||
5. Apply matching `postAdapter` transforms
|
||||
6. Validate and write
|
||||
|
||||
**Rationale**:
|
||||
- Keeps adapters focused on tool formatting, not scattered behavioral rewrites
|
||||
- Makes agent-specific modifications explicit and testable
|
||||
- Replaces ad-hoc transform calls in `init`/`update`
|
||||
- Enables neutral fallback rendering when a tool profile is not verified for literal command syntax
|
||||
|
||||
### 4. Fallback policy for unverified command surfaces
|
||||
|
||||
**Decision**: When a tool profile has `commandSurface.verified === false`, command tokens SHALL render to neutral workflow guidance instead of literal slash-command strings.
|
||||
|
||||
Examples:
|
||||
- Literal (verified): `Run {{cmd.apply}}`
|
||||
- Neutral (unverified): `Run the Apply workflow` or `use the apply skill`
|
||||
|
||||
**Rationale**:
|
||||
- Prevents confidently wrong guidance in generated artifacts
|
||||
- Allows incremental tool-surface verification without blocking rollout
|
||||
- Keeps templates stable while rendering policy evolves
|
||||
|
||||
### 5. Shared `ArtifactSyncEngine`
|
||||
|
||||
**Decision**: Introduce a single orchestration engine used by all generation entry points.
|
||||
|
||||
Responsibilities:
|
||||
- Build generation plan from `(workflows × selected tools × artifact kinds)`
|
||||
- Run render/transform/adapter pipeline
|
||||
- Validate outputs
|
||||
- Write files and return result summary
|
||||
|
||||
**Rationale**:
|
||||
- Removes duplicated loops and divergent behavior across init/update paths
|
||||
- Enables dry-run and future preview features without re-implementing logic
|
||||
- Improves reliability of updates and legacy migrations
|
||||
|
||||
### 6. Validation + parity guardrails
|
||||
|
||||
**Decision**: Add strict checks in tests (and optional runtime assertions in dev builds) for:
|
||||
|
||||
- Required skill metadata fields (`license`, `compatibility`, `metadata`) present for all manifest entries
|
||||
- Projection consistency (skills, commands, detection names derived from manifest)
|
||||
- Tool profile consistency (adapter existence, expected capabilities)
|
||||
- Token coverage checks (no unresolved `{{...}}` tokens in rendered outputs)
|
||||
- Tool command-surface verification matrix and fallback expectations
|
||||
- Golden/parity output for key workflows/tools
|
||||
|
||||
**Rationale**:
|
||||
- Converts prior review issues into enforced invariants
|
||||
- Preserves output fidelity while enabling internal refactors
|
||||
- Makes regressions obvious during CI
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
**Risk: Migration complexity**
|
||||
A broad refactor can destabilize generation paths.
|
||||
→ Mitigation: introduce in phases with parity tests before cutover.
|
||||
|
||||
**Risk: Over-abstraction**
|
||||
Too many layers can obscure simple flows.
|
||||
→ Mitigation: keep interfaces minimal and colocate registries with generation code.
|
||||
|
||||
**Trade-off: More upfront structure**
|
||||
Adding manifest/profile/transform registries increases conceptual surface area.
|
||||
→ Accepted: this cost is offset by reduced drift and easier extension.
|
||||
|
||||
## Implementation Approach
|
||||
|
||||
1. Build manifest + profile + transform types and registries behind current public API
|
||||
2. Tokenize command/terminology references in workflow templates
|
||||
3. Rewire `getSkillTemplates`/`getCommandContents` to derive from manifest
|
||||
4. Introduce `ArtifactSyncEngine` and switch `init` to use it with parity checks
|
||||
5. Switch `update` and legacy upgrade flows to same engine
|
||||
6. Remove duplicate/hardcoded lists after parity is green
|
||||
@@ -0,0 +1,53 @@
|
||||
## Why
|
||||
|
||||
The recent split of `skill-templates.ts` into workflow modules improved readability, but the generation pipeline is still fragmented across multiple layers:
|
||||
|
||||
- Workflow definitions are split from projection logic (`getSkillTemplates`, `getCommandTemplates`, `getCommandContents`)
|
||||
- Tool capability and compatibility are spread across `AI_TOOLS`, `CommandAdapterRegistry`, and hardcoded lists like `SKILL_NAMES`
|
||||
- Agent/tool-specific transformations are applied in different places (`init`, `update`, and adapter code)
|
||||
- Command and terminology references are currently hardcoded in workflow text, but tool invocation surfaces vary (`/opsx:apply`, `/opsx-apply`, `/opsx/apply`, and tool-specific naming)
|
||||
- Artifact writing logic is duplicated across `init`, `update`, and legacy-upgrade flow
|
||||
|
||||
This fragmentation creates drift risk (missing exports, missing metadata parity, mismatched counts/support) and makes future workflow/tool additions slower and less predictable.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Introduce a canonical `WorkflowManifest` as the single source of truth for all workflow artifacts
|
||||
- Introduce a `ToolProfileRegistry` to centralize tool capabilities (skills path, command adapter, transforms)
|
||||
- Introduce a first-class transform pipeline with explicit phases (`preAdapter`, `postAdapter`) and scopes (`skill`, `command`, `both`)
|
||||
- Introduce a shared `ArtifactSyncEngine` used by `init`, `update`, and legacy upgrade paths
|
||||
- Add tokenized workflow text rendering so command references and tool terminology are resolved per tool profile at generation time
|
||||
- Add explicit command-surface profiles per tool (pattern, namespace/path style, alias support, verification status)
|
||||
- Add safe fallback behavior: when a tool command surface is not verified, render neutral workflow guidance (for example skill/workflow names) instead of potentially wrong literal command strings
|
||||
- Add strict validation and test guardrails to preserve fidelity during migration and future changes
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `template-artifact-pipeline`: Unified workflow manifest, tool profile registry, token-aware transform pipeline, and sync engine for skill/command generation
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `command-generation`: Extended to support ordered transform phases around adapter rendering
|
||||
- `cli-init`: Uses shared artifact sync orchestration instead of bespoke loops
|
||||
- `cli-update`: Uses shared artifact sync orchestration instead of bespoke loops
|
||||
|
||||
## Impact
|
||||
|
||||
- **Primary refactor area**:
|
||||
- `src/core/templates/*`
|
||||
- `src/core/shared/skill-generation.ts`
|
||||
- `src/core/command-generation/*`
|
||||
- `src/core/init.ts`
|
||||
- `src/core/update.ts`
|
||||
- `src/core/shared/tool-detection.ts`
|
||||
- **Testing additions**:
|
||||
- Manifest completeness tests (workflows, required metadata, projection parity)
|
||||
- Transform ordering and applicability tests
|
||||
- Tool command-surface/terminology profile validation tests
|
||||
- End-to-end parity tests for generated skill/command outputs across tools
|
||||
- **User-facing behavior**:
|
||||
- No new CLI surface area required
|
||||
- Generated text may become more tool-accurate for verified tool profiles
|
||||
- Generated text may intentionally use neutral workflow wording for unverified tools to avoid incorrect slash-command guidance
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
# template-artifact-pipeline Specification
|
||||
|
||||
## Purpose
|
||||
|
||||
Define a unified architecture for workflow template generation that centralizes workflow definitions, tool capability wiring, transform execution, and artifact synchronization while preserving output fidelity.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Canonical Workflow Manifest
|
||||
|
||||
The system SHALL define a canonical workflow manifest as the single source of truth for generated skill and command artifacts.
|
||||
|
||||
#### Scenario: Register workflow once
|
||||
|
||||
- **WHEN** a workflow (for example `explore`, `ff`, or `onboard`) is added or modified
|
||||
- **THEN** its canonical definition SHALL be registered once in the workflow manifest
|
||||
- **AND** skill/command projections SHALL be derived from that manifest
|
||||
- **AND** duplicate hand-maintained lists SHALL NOT be required
|
||||
|
||||
#### Scenario: Required skill metadata
|
||||
|
||||
- **WHEN** defining a workflow skill entry in the manifest
|
||||
- **THEN** it SHALL include required metadata fields (`license`, `compatibility`, and `metadata`)
|
||||
- **AND** generation SHALL use those values or explicit defaults in a consistent way for all workflows
|
||||
|
||||
### Requirement: Tool Profile Registry
|
||||
|
||||
The system SHALL define a tool profile registry that captures generation capabilities per tool.
|
||||
|
||||
#### Scenario: Resolve tool capabilities
|
||||
|
||||
- **WHEN** generating artifacts for a selected tool
|
||||
- **THEN** the system SHALL resolve a tool profile that declares skill path capability, command adapter linkage, and transform set
|
||||
- **AND** tools with skills support but no command adapter SHALL be handled explicitly without implicit fallback behavior
|
||||
|
||||
#### Scenario: Capability consistency validation
|
||||
|
||||
- **WHEN** running validation checks
|
||||
- **THEN** the system SHALL detect mismatches between configured tools, profile definitions, and registered adapters
|
||||
- **AND** fail with actionable errors in development/CI
|
||||
|
||||
### Requirement: Ordered Transform Pipeline
|
||||
|
||||
The system SHALL support ordered artifact transforms with explicit scope and phase semantics.
|
||||
|
||||
#### Scenario: Execute pre-adapter and post-adapter transforms
|
||||
|
||||
- **WHEN** generating an artifact
|
||||
- **THEN** matching transforms SHALL execute in deterministic order based on phase and priority
|
||||
- **AND** `preAdapter` transforms SHALL run before command adapter formatting
|
||||
- **AND** `postAdapter` transforms SHALL run after adapter formatting
|
||||
|
||||
#### Scenario: Apply tool-specific rewrites declaratively
|
||||
|
||||
- **WHEN** a tool requires instruction rewrites (for example command reference syntax changes)
|
||||
- **THEN** those rewrites SHALL be implemented as registered transforms with explicit applicability predicates
|
||||
- **AND** generation entry points SHALL NOT implement ad-hoc rewrite logic
|
||||
|
||||
### Requirement: Shared Artifact Sync Engine
|
||||
|
||||
The system SHALL provide a shared artifact sync engine used by all generation entry points.
|
||||
|
||||
#### Scenario: Init and update use same engine
|
||||
|
||||
- **WHEN** `openspec init` or `openspec update` writes skills/commands
|
||||
- **THEN** both flows SHALL use the same orchestration engine for planning, rendering, validating, and writing artifacts
|
||||
- **AND** behavior differences SHALL be configuration-driven rather than separate duplicated loops
|
||||
|
||||
#### Scenario: Legacy upgrade path reuses engine
|
||||
|
||||
- **WHEN** legacy cleanup triggers artifact regeneration
|
||||
- **THEN** the regeneration path SHALL use the same shared engine
|
||||
- **AND** generated outputs SHALL follow the same transform and validation rules
|
||||
|
||||
### Requirement: Fidelity Guardrails
|
||||
|
||||
The system SHALL enforce guardrails that prevent output drift during refactors.
|
||||
|
||||
#### Scenario: Projection parity checks
|
||||
|
||||
- **WHEN** CI runs template generation tests
|
||||
- **THEN** it SHALL verify manifest-derived projections remain consistent (workflows, command IDs, skill directories)
|
||||
- **AND** detect missing exports or missing workflow registration
|
||||
|
||||
#### Scenario: Output parity checks
|
||||
|
||||
- **WHEN** running parity tests for representative workflow/tool combinations
|
||||
- **THEN** generated artifacts SHALL remain behaviorally equivalent to approved baselines unless intentionally changed
|
||||
- **AND** intentional changes SHALL be captured in explicit spec/proposal updates
|
||||
@@ -0,0 +1,47 @@
|
||||
## 1. Manifest Foundation
|
||||
|
||||
- [ ] 1.1 Create canonical workflow manifest registry under `src/core/templates/`
|
||||
- [ ] 1.2 Define shared manifest types for workflow IDs, skill metadata, and optional command descriptors
|
||||
- [ ] 1.3 Migrate existing workflow registration (`getSkillTemplates`, `getCommandTemplates`, `getCommandContents`) to derive from the manifest
|
||||
- [ ] 1.4 Preserve existing external exports/API compatibility for `src/core/templates/skill-templates.ts`
|
||||
|
||||
## 2. Tool Profile Layer
|
||||
|
||||
- [ ] 2.1 Add `ToolProfile` types and `ToolProfileRegistry`
|
||||
- [ ] 2.2 Map all currently supported tools to explicit profile entries
|
||||
- [ ] 2.3 Wire profile lookups to command adapter resolution and skills path resolution
|
||||
- [ ] 2.4 Add per-tool `commandSurface` metadata (pattern, aliases, `verified` flag)
|
||||
- [ ] 2.5 Add per-tool terminology metadata (for example change/workflow/command labels)
|
||||
- [ ] 2.6 Replace hardcoded detection arrays (for example `SKILL_NAMES`) with manifest-derived values
|
||||
|
||||
## 3. Transform Pipeline
|
||||
|
||||
- [ ] 3.1 Introduce transform interfaces (`scope`, `phase`, `priority`, `applies`, `transform`)
|
||||
- [ ] 3.2 Implement transform runner with deterministic ordering
|
||||
- [ ] 3.3 Add token renderer transform for command + terminology tokens (`{{cmd.*}}`, `{{term.*}}`)
|
||||
- [ ] 3.4 Implement neutral fallback rendering for tools with unverified command surfaces
|
||||
- [ ] 3.5 Migrate OpenCode command reference rewrite to transform pipeline
|
||||
- [ ] 3.6 Remove ad-hoc transform invocation from `init` and `update`
|
||||
|
||||
## 4. Artifact Sync Engine
|
||||
|
||||
- [ ] 4.1 Create shared artifact sync engine for generation planning + rendering + writing
|
||||
- [ ] 4.2 Integrate engine into `init` flow
|
||||
- [ ] 4.3 Integrate engine into `update` flow
|
||||
- [ ] 4.4 Integrate engine into legacy-upgrade artifact generation path
|
||||
|
||||
## 5. Validation and Tests
|
||||
|
||||
- [ ] 5.1 Add manifest completeness tests (metadata required fields, command IDs, dir names)
|
||||
- [ ] 5.2 Add tool-profile consistency tests (skillsDir support, adapter/profile alignment, command-surface metadata)
|
||||
- [ ] 5.3 Add token rendering tests (all tokens resolved, per-tool rendering correctness)
|
||||
- [ ] 5.4 Add fallback tests for unverified tool command surfaces
|
||||
- [ ] 5.5 Add transform applicability/order tests
|
||||
- [ ] 5.6 Expand parity tests for representative workflow/tool matrix
|
||||
- [ ] 5.7 Run full test suite and verify generated artifacts remain stable
|
||||
|
||||
## 6. Cleanup and Documentation
|
||||
|
||||
- [ ] 6.1 Remove superseded helper code and duplicate write loops after cutover
|
||||
- [ ] 6.2 Update internal developer docs for template generation architecture
|
||||
- [ ] 6.3 Document migration guardrails for future workflow/tool additions
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user