Compare commits

..
Author SHA1 Message Date
TabishB 3a88186909 test: align path assertions with canonical helper 2026-04-14 17:53:30 +10:00
TabishB 493605756f fix: prefer native realpath for canonical paths 2026-04-14 17:31:35 +10:00
Tabish Bidiwale 7d07101363 fix: canonicalize workflow artifact paths (#971) 2026-04-14 07:14:11 +00:00
Alfred c0f29044f9 docs: clarify initiative-first workspace model (#969)
* docs: split workspace initiatives from repo-local changes

* docs: align roadmap and explore ux with initiatives
2026-04-13 12:20:24 +00:00
Tabish Bidiwale 7fe45ca330 Fix apply instructions for glob artifact outputs (#967)
* Fix glob artifact resolution in apply instructions

* Enforce file-only literal artifact outputs
2026-04-12 14:35:11 +00:00
Tabish Bidiwale c8e2072e3a fix: detect hidden requirements in main specs (#966)
* fix: detect hidden main spec requirements

* fix: tighten fenced code parsing
2026-04-12 13:59:10 +00:00
Tabish Bidiwale cd5e49346f docs: expand workspace planning explorations (#965)
* docs: add workspace ux explorations

* docs: update workspace architecture direction
2026-04-12 13:17:17 +00:00
Tabish Bidiwale a18d992fa1 fix: suppress ora spinner output when --json flag is used (#960)
When --json is passed, ora spinners wrote progress text to stderr, which
broke JSON parsing for AI agents that combine stdout+stderr. Conditionally
skip spinner creation in status, instructions, and templates commands.

Closes #957
2026-04-12 03:27:55 +00:00
Tabish Bidiwale 4df6a4889b fix: silence telemetry network errors in firewalled environments (#959)
* fix: silence telemetry network errors in firewalled environments

Wrap PostHog fetch with safeTelemetryFetch that catches all network
errors and non-2xx responses, returning a synthetic 204 so PostHog
never throws PostHogFetchNetworkError. Disable retries, remote config,
surveys, and feature flag preloading to eliminate extra network calls.
Add 1s request timeout. Surface telemetry opt-out docs earlier in
README, installation, and CLI reference.

Closes #895

* fix: clear CI env var in telemetry fetch tests

GitHub Actions sets CI=true which disables telemetry, causing PostHog
to never be instantiated and the fetch wrapper tests to fail.

* docs: add telemetry env vars to Environment Variables table

Addresses CodeRabbit review comment.

* docs: remove unnecessary firewall telemetry warnings

Telemetry now fails silently, so users don't need to proactively
disable it. The env vars are still documented in the reference table.

* docs: restore original config get/set examples in cli.md

These examples document how config works, not telemetry opt-out.
2026-04-12 03:21:11 +00:00
openspec-release-bot[bot]andgithub-actions[bot] 9b5007dbc3 Version Packages (#953)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-11 15:43:55 +00:00
Tabish Bidiwale cce787ec40 chore: add changeset for v1.3.0 (#952)
* Add changeset for new tool integrations and bug fixes

* Update changeset with IBM Bob support and pi.dev fix
2026-04-11 15:39:42 +00:00
94d651de8c feat: add support for IBM Bob coding assistant (#886)
* test: add comprehensive tests for Bob Shell adapter

- Add 7 tests covering toolId, file paths, formatting, and edge cases
- Include Bob Shell adapter in cross-platform path handling tests
- All 89 adapter tests now passing
- Ensures Bob Shell adapter works correctly with all 11 workflows

* feat: add Bob Shell adapter support

- Implement Bob Shell command adapter with YAML frontmatter
- Register adapter in CommandAdapterRegistry
- Export adapter from adapters/index.ts
- Add Bob Shell to AI_TOOLS configuration
- Generates commands in .bob/commands/opsx-<id>.md format
- Supports all 11 workflows via custom profile system

* docs: add Bob Shell to supported tools documentation

- Add Bob Shell to README.md supported tools list
- Update docs/supported-tools.md with Bob Shell entry
- Document .bob/commands/opsx-<id>.md command path pattern
- Note that Bob Shell uses commands, not Agent Skills spec

* docs: add Bob Shell support proposal and design documentation

- Add comprehensive proposal for Bob Shell integration
- Document command structure and file format
- Include implementation plan and success criteria
- Preserve change documentation for future reference

* chore: update dependencies and gitignore

- Update package-lock.json with latest dependencies
- Add .bob/ to gitignore (test output directory)

* chore: update gitignore to exclude .bob directory

* openspec change not needed for project, should be kept local

* Update reference from Bob Shell to IBM Bob Shell

* fix: transform command references and add argument-hint for Bob adapter

Bob derives command names from filenames (opsx-apply.md → /opsx-apply),
so body text referencing /opsx:apply is incorrect. Apply the same
transformToHyphenCommands rewrite that opencode.ts uses. Also add
argument-hint frontmatter to match peer adapters (auggie, codebuddy, etc).

---------

Co-authored-by: TabishB <tabishbidiwale@gmail.com>
Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com>
2026-04-11 15:31:45 +00:00
Tabish Bidiwale 040e382d64 test: fix windows powershell ci (#951) 2026-04-11 15:17:00 +00:00
Tabish Bidiwale caafd7c9bf fix: pi.dev command reference transforms and template args passing (#950)
* fix: pi.dev prompt naming and template args passing (#912)

Fix two pi.dev integration bugs:
- Use colon-based filenames (opsx:explore.md) so CLI commands render as
  /opsx:explore instead of /opsx-explore
- Inject $@ into template body so user arguments are passed through

Adds getLegacyFilePaths to ToolCommandAdapter for migration-safe cleanup
of old hyphenated files during init/update.

* fix: pi.dev command references and template args passing (#912)

- Transform /opsx: references to /opsx- in Pi command bodies and skills,
  matching the hyphenated filename convention (same approach as OpenCode)
- Inject $@ into template body so user arguments are passed through

Pi uses the filename (minus .md) as the slash command name, so
opsx-propose.md becomes /opsx-propose. This keeps filenames
cross-platform safe while ensuring command references in the body
match the actual command names.
2026-04-11 15:00:46 +00:00
Tabish Bidiwale 144528257d fix: make completion install opt-in, fix PowerShell encoding corruption (#949)
* fix: make shell completion install opt-in and fix PowerShell profile encoding corruption (#948)

The postinstall hook silently modified users' shell profiles and corrupted
UTF-16 LE PowerShell profiles by forcing all reads/writes through UTF-8.
Now postinstall only prints a tip, and the PowerShell installer preserves
file encoding via BOM detection on read/write.

* Address review: skip profile on any read error, log warnings, clean up UTF-16 BE handling

- configureProfile: skip profile on any non-ENOENT error instead of falling
  through with empty content (could overwrite real profile)
- removeProfileConfig: log warning on unexpected read errors instead of
  silently swallowing
- detectEncoding: throw directly for UTF-16 BE instead of using sentinel value
- Add test for UTF-16 BE profile rejection
2026-04-11 13:58:24 +00:00
Irina ChichikovaandTabishB af0b3418d0 Add support for Junie from JetBrains tool and command generation (#853)
* Add support for Junie from JetBrains tool and command generation

* Expand Junie support to include `opsx` file patterns and update documentation accordingly

---------

Co-authored-by: TabishB <tabishbidiwale@gmail.com>
2026-04-10 01:01:38 +00:00
7fd5417ed0 style: Fix formatting of user facing and agent facing diagrams and markdown tables (#892)
* style: Fix formatting of user facing and agent facing diagrams and markdown tables

* test: update template parity hashes for formatting changes

---------

Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com>
Co-authored-by: TabishB <tabishbidiwale@gmail.com>
2026-04-09 07:26:45 +00:00
mrack688andMarck 5ac1e12b83 feat: add Lingma IDE support to configuration (#864)
feat: add Lingma IDE support to configuration
feat: add Lingma IDE support to configuration

Co-authored-by: Marck <6992917@qq.com>
2026-04-09 06:25:27 +00:00
Gregor Albrecht fd7ad273c7 Fix formatting in concepts.md (#882) 2026-04-09 03:34:41 +00:00
Harry James Hall ea6f380fea feat: add ForgeCode tool support (#941) 2026-04-09 03:13:30 +00:00
XingxingandClaude Opus 4.6 765df47ad3 fix(init): prevent false GitHub Copilot auto-detection from bare .github/ directory (#917)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 03:13:04 +00:00
Alfred 64d476f8b9 ci: add merge_group support for merge queue (#918) 2026-04-05 06:56:59 +00:00
afdca0d5da fix(status): exit gracefully when no changes exist (#759)
* fix(status): exit gracefully when no changes exist (#714)

Extract `getAvailableChanges` as a public function from `validateChangeExists`
and use it in `statusCommand` to detect the no-changes case early. Returns a
friendly message (text and JSON modes) with exit code 0 instead of a fatal error.

Generated with Claude Code using claude-opus-4-6.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: fix design risk description and proposal accuracy

Address CodeRabbit review feedback:
- Fix contradictory risk description in design.md (double-read happens
  when changes exist, not when they don't)
- Clarify in proposal.md that validateChangeExists was internally
  refactored to delegate to getAvailableChanges

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(status): narrow catch in getAvailableChanges to ENOENT only

Return [] only when the changes directory doesn't exist (ENOENT).
Rethrow other errors (EACCES, etc.) so real filesystem issues
surface instead of being silently masked as "no changes".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com>
2026-02-27 00:52:22 -08:00
61eb999f7c fix(opencode): use plural commands/ directory to match OpenCode convention (#760)
* fix(opencode): use plural `commands/` directory to match OpenCode convention

The OpenCode adapter was using `.opencode/command/` (singular) but OpenCode's
official documentation specifies `.opencode/commands/` (plural). This aligns
with every other adapter in the codebase. Legacy cleanup updated to detect
old singular-path artifacts. Fixes #748.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(legacy): detect both opsx-* and openspec-* patterns, auto-cleanup in CI

- Extend LegacySlashCommandPattern.pattern to accept string | string[]
- OpenCode legacy entry now detects both opsx-*.md and openspec-*.md
- Auto-cleanup legacy artifacts in non-interactive mode instead of
  aborting with exit 1 (safe: slash commands are OpenSpec-managed,
  config cleanup only removes markers)
- Add 7 tests (6 legacy detection + 1 non-interactive init)
- Update spec with array pattern support and auto-cleanup scenario

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: update task description to reflect dual-pattern support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com>
2026-02-27 00:08:22 -08:00
3d3bf96061 docs: fix openspec status examples in cli.md (#761)
* docs: fix `openspec status` examples in cli.md to match actual CLI output

The text and JSON output examples for the status command used incorrect
field names, indicators, and structure. Updated to match real CLI output,
validated against a test project with partial artifacts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove spec change and changeset for docs-only fix

Per reviewer feedback — docs fixes don't need a spec change or
version bump.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com>
2026-02-26 23:37:28 -08:00
JabinGP d199dfa407 docs: fix docs/concepts nested code-block format (#763) 2026-02-26 10:15:27 +00:00
Tabish Bidiwale d7d186088e docs: realign defaults, profile workflows, and tool references (#746)
* docs: realign defaults, workflows, and tool references

* docs: resolve Trae wording and opsx diagram alignment

* chore: ignore codex workspace directory
2026-02-23 18:27:23 -08:00
openspec-release-bot[bot]andgithub-actions[bot] 6a3a1263fe Version Packages (#751)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-02-23 15:43:08 -08:00
Tabish Bidiwale 1e94443a35 Add changeset for profiles, Pi, Kiro, and bug fixes (#747) 2026-02-23 15:37:30 -08:00
Tabish Bidiwale a0608d0bab Sync update to prune deselected workflows (#741) 2026-02-22 05:35:01 -08:00
e4c32dbe07 feat: add support for Pi (pi.dev) coding agent (#735)
* feat: add support for Pi (pi.dev) coding agent

Add Pi as a supported tool in OpenSpec with full adapter implementation.

Changes:
- Create pi.ts adapter for command generation
- Register adapter in registry and export from index
- Add Pi to AI_TOOLS config with .pi skills directory
- Add tests for piAdapter following existing patterns
- Update supported-tools.md documentation

Pi uses:
- Skills: .pi/skills/ (Agent Skills standard)
- Prompts: .pi/prompts/*.md (with description frontmatter)

Closes #732

* fix: add Pi to LEGACY_SLASH_COMMAND_PATHS for test compliance

* style: add trailing newline to pi.ts

* fix: correct legacy cleanup pattern for Pi (opsx-*.md not openspec-*.md)

* fix: add YAML escaping for Pi adapter to handle special characters in descriptions

- Add escapeYamlValue() function to properly escape YAML special characters
- Apply escaping to description field in frontmatter
- Add tests for YAML special character escaping (colons, quotes, newlines)

This follows the same pattern used by cursor, claude, and windsurf adapters.

* fix: remove Pi from LEGACY_SLASH_COMMAND_PATHS

Pi was never supported in pre-1.0 versions, so no legacy cleanup is needed.
Per reviewer feedback: this is only for tools from pre-1.0 OpenSpec.

* test: relax legacy-cleanup registry coverage invariant

---------

Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com>
Co-authored-by: TabishB <tabishbidiwale@gmail.com>
2026-02-21 15:34:40 -08:00
Tabish Bidiwale 2d4c98e196 Simplify profile sync + strengthen commands-only coverage (#736)
* Improve profile sync flows and add coverage for commands-only edge cases

* Fix migration workflow preservation and add coverage
2026-02-21 05:48:50 -08:00
Tabish Bidiwale be6659cd39 Add OpenSpec proposals for stacking, install scope, and command surfaces (#733)
* Add OpenSpec change proposals for stacking and scope

* Address review feedback across change proposals

* Preserve legacy install-scope behavior with migration path

* Address remaining review threads across spec proposals

* Address latest review feedback on split and command-surface specs

* Clarify split and composition semantics from latest review
2026-02-21 00:42:15 -08:00
Tabish Bidiwale 4ba26902df feat: simplify skill installation with profiles and smart defaults (#726)
* feat: implement simplified skill installation with profiles and smart defaults

Introduces a profile system (core/custom) to reduce the default workflow
count from 10 to 4, auto-detects AI tools during init, adds a new
`propose` workflow combining new+ff, fixes multi-select keybindings,
and adds backwards-compatible migration for existing users.

* feat: harden update config drift, command-only detection, and init profile validation

Address post-implementation review findings: update now detects profile/delivery
drift even when template versions are current, recognizes command-only installs
as configured tools, init validates --profile values and applies delivery cleanup
on re-init. Specs and design docs updated with new scenarios and rationale.

* fix: address AI reviewer feedback on config, detection, and test cleanup

- Add error handling for execSync in config profile apply and use static import
- Fix config list showing "(explicit)" for core profile workflows misleadingly
- Add missing 'openspec-onboard' to SKILL_NAMES for parity with COMMAND_IDS
- Remove unused fsSync import in init tests
- Fix configTempDir leak in test afterEach cleanup

* docs: add qa smoke harness change proposal
2026-02-19 18:21:06 -08:00
Tabish Bidiwale 5fd8e9d66c feat: simplify skill installation with profiles and smart defaults init (#719)
* feat: add change proposal for simplified skill installation

Introduces a change proposal to simplify the init flow and skill installation:

- Zero-question init with sensible defaults (core profile, both delivery)
- Auto-detect AI tools from existing directories (.claude/, .cursor/, etc.)
- Profile system: core (4 workflows), extended (11 workflows), custom
- Delivery config: both, skills, commands
- New `propose` workflow combining new + ff
- Fix tool selection UX (space to select, enter to confirm)

Key design decisions:
- Extend existing global config (~/.config/openspec/config.json)
- Profile install/uninstall immediately mutates filesystem
- Safe deletion via SKILL_NAMES and COMMAND_IDS constant lookups
- Filesystem as truth for installed workflows

Also adds rules to openspec/config.yaml to prevent overengineering
(explicit lookups over pattern matching).

* chore: add missing .openspec.yaml metadata file

* fix: address PR review feedback

Issues fixed:
- Clarify workflow count: extended = existing 10 + new propose = 11
- Rename spec: tool-auto-detection → available-tools (matches proposal)
- Change "identical" to "functionally equivalent" in propose spec
- Add profile change notification when install/uninstall changes profile
- Specify edge case: uninstall workflow from current non-custom profile
- Specify behavior when --apply-profile confirmation is declined
- Fix section numbering in design.md (6, 6a, 6b, 8)
- Add scaffolding verification tasks (verify .openspec.yaml exists)
- Specify case sensitivity mechanism: use fs.existsSync, let OS handle it

* fix: address CodeRabbit review comments

- Add language specifiers to fenced code blocks in proposal.md
- Add COMMAND_IDS update for propose in modified files list
- Make init success message tool-aware (colon vs hyphen syntax)
- Fix grammar: "Skills-only" and "Commands-only" in delivery-config
- Specify config get delivery output when field absent: "both (default)"
- Add profile set scenarios: config-only vs --apply-profile with filesystem mutation
- Add error scenarios for invalid profile name and unknown workflow
- Add scenario for existing config without profile field
- Mark active profile in profile list output
- Enumerate artifacts in propose basic scenario
- Fix propose equivalence to use skill syntax consistently
- Specify continue/create new branches in propose
- Remove out-of-scope command assertion from skill-generation spec
- Reference SKILL_NAMES constant instead of vague "existing templates"
- Fix design.md: SKILL_NAMES AND COMMAND_IDS (not "only")
- Specify overwrite semantics for refresh/update
- Add task 6.8: propose to COMMAND_IDS
- Fix function name: getAvailableTools() not detectInstalledTools()

* refactor: simplify skill installation design based on review

- Update design to use existing CLAUDE.md mechanisms
- Add cli-update spec for managing skill updates
- Clarify profile system and user config interactions
- Add explorations directory with design notes
- Update docs with clearer concepts

* docs: rename zero-question init to smart defaults init

Clarify that init auto-detects tools and asks for confirmation,
rather than being completely question-free. Update examples to
show the tool confirmation UI.

* docs: add explore workflow tasks and UX exploration

- Add tasks to update explore.ts references to /opsx:propose
- Create exploration note for deeper explore → propose UX questions
- Captures open questions about exploration artifacts, lifecycle,
  context handoff, and transition smoothness

* fix: address PR review feedback from 1code-async

- Add ## Purpose sections to all 10 spec files (required by schema)
- Add specs/ to propose workflow's first-time user guidance scenario
- Add --tools flag scenario for interactive mode in cli-init/spec.md
- Clarify that profile changes take effect on next init/update
- Fix design snippet to use AI_TOOLS config instead of TOOL_DIRS constant
- Add explicit Windsurf detection scenario to available-tools/spec.md
- Mark tasks 10.2-10.3 as follow-up work (out of scope)
- Fix capability name: init → cli-init in proposal.md
2026-02-18 02:11:35 -08:00
Tabish Bidiwale 4108563731 Bulk archive completed changes and normalize source specs (#716)
* chore: bulk archive completed changes and normalize specs

* docs: finalize spec purposes and align init workflow scenarios

* test: guard source specs against placeholders and delta headers

* docs: resolve remaining spec review nits
2026-02-16 21:28:27 -08:00
anilkmr-a2zandTabish Bidiwale fbef555041 feat: add Kiro CLI support (#707)
Add Kiro (AWS AI IDE) as a supported tool with command adapter
that writes to .kiro/prompts/ with YAML frontmatter.

- Add Kiro to AI_TOOLS registry in config.ts
- Create kiro.ts adapter (GitHub Copilot pattern)
- Register adapter in index.ts and registry.ts
- Add legacy cleanup path for migration
- Update supported-tools.md documentation

Generated with Kiro CLI using Claude Opus 4.6

Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com>
2026-02-16 08:34:42 +00:00
Tabish Bidiwale 92731e2263 refactor: split skill templates into workflow modules (#698)
* refactor: split skill templates into workflow modules

* fix: align template index exports and parity docs

* fix: add standard metadata to feedback skill template

* fix: add ff command guardrail for context and rules

* spec: add unified template generation pipeline proposal
2026-02-15 23:13:52 -08:00
1code-async[bot]andClaude Opus 4.6 c574e7992d docs: clarify GitHub Copilot CLI limitation for custom prompts (#676)
* docs: clarify GitHub Copilot CLI does not support custom prompt files

GitHub Copilot's .github/prompts/*.prompt.md files are only recognized
as custom slash commands in IDE extensions (VS Code, JetBrains, Visual
Studio). The Copilot CLI does not support them (github/copilot-cli#618).
This updates the docs to clarify the limitation and point users to the
.github/agents/ workaround.

Closes #671

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: use distinct footnote markers for Codex and Copilot

Addresses review feedback: the shared `*` marker was ambiguous across
Markdown renderers. Now uses `*` for Codex and `**` for Copilot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-06 20:07:41 -08:00
pig 62d4391268 fix: improve Windows compatibility in tests (#646)
- Replace Unix 'cat' command with fs.readFile in spec.test.ts

- Replace 'mkdir -p' and 'bash' commands with fs.mkdir/writeFile in validate.enriched-output.test.ts

- Skip symlink test on Windows (requires admin privileges) in file-system.test.ts
2026-02-01 22:57:47 -08:00
Oleksandr Kruk 4573c28048 fix(docs): Update migration guide action diagram formatting (#644) 2026-02-01 16:03:06 -08:00
Tabish Bidiwale 0541f93ddd fix(onboard): add Windows PowerShell alternatives for shell commands (#638)
* fix(onboard): replace broken preflight check and add Windows compatibility

The onboarding preflight used `openspec status --json` to detect if a
project was initialized, but that command requires an existing change
to succeed. After a fresh `openspec init` (no changes yet), it always
failed — causing the onboarding to incorrectly tell users to run init
again.

Replace with `openspec --version` to verify the CLI is installed.

Also add Windows PowerShell alternatives for all platform-specific
shell commands in the onboarding skill:
- `2>&1 ||` → `; if ($LASTEXITCODE -ne 0) {}`
- `2>/dev/null` → `2>$null`
- `mkdir -p` → `New-Item -ItemType Directory -Force`

* fix(onboard): address PR review feedback for PowerShell commands

Use Get-Command for robust CLI detection instead of $LASTEXITCODE
(which stays stale when a command isn't found), and use forward slashes
in PowerShell paths for consistency with Unix commands.
2026-01-31 19:30:43 -08:00
Tabish Bidiwale be51bcbc6a fix(onboard): replace broken preflight check with direct config file test (#637)
The onboarding preflight used `openspec status --json` to detect if a
project was initialized, but that command requires an existing change
to succeed. After a fresh `openspec init` (no changes yet), it always
failed — causing the onboarding to incorrectly tell users to run init
again.

Replace with two targeted checks:
- `openspec --version` to verify the CLI is installed
- `test -f openspec/config.yaml` to verify project initialization
2026-01-31 18:46:50 -08:00
CodingVillainandClaude Opus 4.5 1d34e72f10 fix: use Skill tool for sync invocation in archive templates (#632)
* fix: use Skill tool for sync invocation in archive templates

Update archive skill templates to properly instruct the AI to use
the Skill tool to invoke sync commands instead of executing command
logic directly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: use Task tool subagent for sync in archive templates

Skill tool terminates after completion and doesn't return control to the
caller, causing archive to not continue after sync. Changed to spawn a
subagent via Task tool which properly returns control after completion.

Also updated opsx:sync references to openspec-sync-specs for semantic
coherence across templates.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 18:23:44 -08:00
228 changed files with 23961 additions and 4491 deletions
+7 -5
View File
@@ -3,6 +3,8 @@ name: CI
on:
pull_request:
branches: [main]
merge_group:
branches: [main]
push:
branches: [main]
workflow_dispatch:
@@ -42,7 +44,7 @@ jobs:
name: Test
runs-on: ubuntu-latest
timeout-minutes: 10
if: github.event_name == 'pull_request'
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
steps:
- name: Checkout code
@@ -81,7 +83,7 @@ jobs:
name: Test (${{ matrix.label }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
if: github.event_name != 'pull_request'
if: github.event_name == 'push'
strategy:
fail-fast: false
matrix:
@@ -242,7 +244,7 @@ jobs:
validate-changesets:
name: Validate Changesets
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -275,7 +277,7 @@ jobs:
name: All checks passed
runs-on: ubuntu-latest
needs: [test_pr, lint, nix-flake-validate]
if: always() && github.event_name == 'pull_request'
if: always() && (github.event_name == 'pull_request' || github.event_name == 'merge_group')
steps:
- name: Verify all checks passed
run: |
@@ -301,7 +303,7 @@ jobs:
name: All checks passed
runs-on: ubuntu-latest
needs: [test_matrix, lint, nix-flake-validate]
if: always() && github.event_name != 'pull_request'
if: always() && github.event_name == 'push'
steps:
- name: Verify all checks passed
run: |
+6
View File
@@ -153,3 +153,9 @@ result
# OpenCode
.opencode/
opencode.json
# Codex
.codex/
# Bob
.bob/
+43
View File
@@ -1,5 +1,48 @@
# @fission-ai/openspec
## 1.3.0
### Minor Changes
- [#952](https://github.com/Fission-AI/OpenSpec/pull/952) [`cce787e`](https://github.com/Fission-AI/OpenSpec/commit/cce787ec4083da2b27781f6786f5ce0002909a7b) Thanks [@TabishB](https://github.com/TabishB)! - ### New Features
- **Junie support** — Added tool and command generation for JetBrains Junie
- **Lingma IDE support** — Added configuration support for Lingma IDE
- **ForgeCode support** — Added tool support for ForgeCode
- **IBM Bob support** — Added support for IBM Bob coding assistant
### Bug Fixes
- **Shell completions opt-in** — Completion install is now opt-in, fixing PowerShell encoding corruption
- **Copilot auto-detection** — Prevented false GitHub Copilot detection from a bare `.github/` directory
- **pi.dev command generation** — Fixed command reference transforms and template argument passing
### Patch Changes
- [#760](https://github.com/Fission-AI/OpenSpec/pull/760) [`61eb999`](https://github.com/Fission-AI/OpenSpec/commit/61eb999f7c6c0fc98d2e7f3678756fce6a3f4378) Thanks [@fsilvaortiz](https://github.com/fsilvaortiz)! - fix: OpenCode adapter now uses `.opencode/commands/` (plural) to match OpenCode's official directory convention. Fixes #748.
- [#759](https://github.com/Fission-AI/OpenSpec/pull/759) [`afdca0d`](https://github.com/Fission-AI/OpenSpec/commit/afdca0d5dab1aa109cfd8848b2512333ccad60c3) Thanks [@fsilvaortiz](https://github.com/fsilvaortiz)! - fix: `openspec status` now exits gracefully when no changes exist instead of throwing a fatal error. Fixes #714.
## 1.2.0
### Minor Changes
- [#747](https://github.com/Fission-AI/OpenSpec/pull/747) [`1e94443`](https://github.com/Fission-AI/OpenSpec/commit/1e94443a3551b228eecbc89e95d96d3b9600a192) Thanks [@TabishB](https://github.com/TabishB)! - ### New Features
- **Profile system** — Choose between `core` (4 essential workflows) and `custom` (pick any subset) profiles to control which skills get installed. Manage profiles with the new `openspec config profile` command
- **Propose workflow** — New one-step workflow creates a complete change proposal with design, specs, and tasks from a single request — no need to run `new` then `ff` separately
- **AI tool auto-detection** — `openspec init` now scans your project for existing tool directories (`.claude/`, `.cursor/`, etc.) and pre-selects detected tools
- **Pi (pi.dev) support** — Pi coding agent is now a supported tool with prompt and skill generation
- **Kiro support** — AWS Kiro IDE is now a supported tool with prompt and skill generation
- **Sync prunes deselected workflows** — `openspec update` now removes command files and skill directories for workflows you've deselected, keeping your project clean
- **Config drift warning** — `openspec config list` warns when global config is out of sync with the current project
### Bug Fixes
- Fixed onboard preflight giving a false "not initialized" error on freshly initialized projects
- Fixed archive workflow stopping mid-way when syncing — it now properly resumes after sync completes
- Added Windows PowerShell alternatives for onboard shell commands
## 1.1.1
### Patch Changes
+8 -9
View File
@@ -36,7 +36,7 @@ Our philosophy:
> [!TIP]
> **New workflow now available!** We've rebuilt OpenSpec with a new artifact-guided workflow.
>
> Run `/opsx:onboard` to get started. → [Learn more here](docs/opsx.md)
> Run `/opsx:propose "your idea"` to get started. → [Learn more here](docs/opsx.md)
<p align="center">
Follow <a href="https://x.com/0xTab">@0xTab on X</a> for updates · Join the <a href="https://discord.gg/YctCnvvshC">OpenSpec Discord</a> for help and questions.
@@ -46,17 +46,14 @@ Our philosophy:
Using OpenSpec in a team? [Email here](mailto:teams@openspec.dev) for access to our Slack channel.
<!-- TODO: Add GIF demo of /opsx:new → /opsx:archive workflow -->
<!-- TODO: Add GIF demo of /opsx:propose → /opsx:archive workflow -->
## See it in action
```text
You: /opsx:new add-dark-mode
You: /opsx:propose add-dark-mode
AI: Created openspec/changes/add-dark-mode/
Ready to create: proposal
You: /opsx:ff # "fast-forward" - generate all planning docs
AI: ✓ proposal.md — why we're doing this, what's changing
✓ proposal.md — why we're doing this, what's changing
✓ specs/ — requirements and scenarios
✓ design.md — technical approach
✓ tasks.md — implementation checklist
@@ -101,10 +98,12 @@ cd your-project
openspec init
```
Now tell your AI: `/opsx:new <what-you-want-to-build>`
Now tell your AI: `/opsx:propose <what-you-want-to-build>`
If you want the expanded workflow (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:sync`, `/opsx:bulk-archive`, `/opsx:onboard`), select it with `openspec config profile` and apply with `openspec update`.
> [!NOTE]
> Not sure if your tool is supported? [View the full list](docs/supported-tools.md) – we support 20+ tools and growing.
> Not sure if your tool is supported? [View the full list](docs/supported-tools.md) – we support 25+ tools and growing.
>
> Also works with pnpm, yarn, bun, and nix. [See installation options](docs/installation.md).
+63 -21
View File
@@ -1,6 +1,6 @@
# CLI Reference
The OpenSpec CLI (`openspec`) provides terminal commands for project setup, validation, status inspection, and management. These commands complement the AI slash commands (like `/opsx:new`) documented in [Commands](commands.md).
The OpenSpec CLI (`openspec`) provides terminal commands for project setup, validation, status inspection, and management. These commands complement the AI slash commands (like `/opsx:propose`) documented in [Commands](commands.md).
## Summary
@@ -67,6 +67,8 @@ These options work with all commands:
Initialize OpenSpec in your project. Creates the folder structure and configures AI tool integrations.
Default behavior uses global config defaults: profile `core`, delivery `both`, workflows `propose, explore, apply, archive`.
```
openspec init [path] [options]
```
@@ -83,8 +85,11 @@ openspec init [path] [options]
|--------|-------------|
| `--tools <list>` | Configure AI tools non-interactively. Use `all`, `none`, or comma-separated list |
| `--force` | Auto-cleanup legacy files without prompting |
| `--profile <profile>` | Override global profile for this init run (`core` or `custom`) |
**Supported tools:** `amazon-q`, `antigravity`, `auggie`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `kilocode`, `opencode`, `qoder`, `qwen`, `roocode`, `windsurf`
`--profile custom` uses whatever workflows are currently selected in global config (`openspec config profile`).
**Supported tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `kilocode`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
**Examples:**
@@ -101,6 +106,9 @@ openspec init --tools claude,cursor
# Configure for all supported tools
openspec init --tools all
# Override profile for this run
openspec init --profile core
# Skip prompts and auto-cleanup legacy files
openspec init --force
```
@@ -113,8 +121,9 @@ openspec/
├── changes/ # Proposed changes
└── config.yaml # Project configuration
.claude/skills/ # Claude Code skill files (if claude selected)
.cursor/rules/ # Cursor rules (if cursor selected)
.claude/skills/ # Claude Code skills (if claude selected)
.cursor/skills/ # Cursor skills (if cursor selected)
.cursor/commands/ # Cursor OPSX commands (if delivery includes commands)
... (other tool configs)
```
@@ -122,7 +131,7 @@ openspec/
### `openspec update`
Update OpenSpec instruction files after upgrading the CLI. Re-generates AI tool configuration files.
Update OpenSpec instruction files after upgrading the CLI. Re-generates AI tool configuration files using your current global profile, selected workflows, and delivery mode.
```
openspec update [path] [options]
@@ -428,29 +437,28 @@ openspec status --change add-dark-mode --json
```
Change: add-dark-mode
Schema: spec-driven
Progress: 2/4 artifacts complete
Artifacts:
✓ proposal proposal.md exists
✓ specs specs/ exists
◆ design ready (requires: specs)
○ tasks blocked (requires: design)
Next: Create design using /opsx:continue
[x] proposal
[ ] design
[x] specs
[-] tasks (blocked by: design)
```
**Output (JSON):**
```json
{
"change": "add-dark-mode",
"schema": "spec-driven",
"changeName": "add-dark-mode",
"schemaName": "spec-driven",
"isComplete": false,
"applyRequires": ["tasks"],
"artifacts": [
{"id": "proposal", "status": "complete", "path": "proposal.md"},
{"id": "specs", "status": "complete", "path": "specs/"},
{"id": "design", "status": "ready", "requires": ["specs"]},
{"id": "tasks", "status": "blocked", "requires": ["design"]}
],
"next": "design"
{"id": "proposal", "outputPath": "proposal.md", "status": "done"},
{"id": "design", "outputPath": "design.md", "status": "ready"},
{"id": "specs", "outputPath": "specs/**/*.md", "status": "done"},
{"id": "tasks", "outputPath": "tasks.md", "status": "blocked", "missingDeps": ["design"]}
]
}
```
@@ -767,6 +775,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 +803,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
```
---
@@ -880,6 +920,8 @@ openspec completion uninstall
| Variable | Description |
|----------|-------------|
| `OPENSPEC_TELEMETRY` | Set to `0` to disable telemetry |
| `DO_NOT_TRACK` | Set to `1` to disable telemetry (standard DNT signal) |
| `OPENSPEC_CONCURRENCY` | Default concurrency for bulk validation (default: 6) |
| `EDITOR` or `VISUAL` | Editor for `openspec config edit` |
| `NO_COLOR` | Disable color output when set |
@@ -888,7 +930,7 @@ openspec completion uninstall
## Related Documentation
- [Commands](commands.md) - AI slash commands (`/opsx:new`, `/opsx:apply`, etc.)
- [Commands](commands.md) - AI slash commands (`/opsx:propose`, `/opsx:apply`, etc.)
- [Workflows](workflows.md) - Common patterns and when to use each command
- [Customization](customization.md) - Create custom schemas and templates
- [Getting Started](getting-started.md) - First-time setup guide
+63 -12
View File
@@ -6,23 +6,70 @@ For workflow patterns and when to use each command, see [Workflows](workflows.md
## Quick Reference
### Default Quick Path (`core` profile)
| Command | Purpose |
|---------|---------|
| `/opsx:propose` | Create a change and generate planning artifacts in one step |
| `/opsx:explore` | Think through ideas before committing to a change |
| `/opsx:new` | Start a new change |
| `/opsx:apply` | Implement tasks from the change |
| `/opsx:archive` | Archive a completed change |
### Expanded Workflow Commands (custom workflow selection)
| Command | Purpose |
|---------|---------|
| `/opsx:new` | Start a new change scaffold |
| `/opsx:continue` | Create the next artifact based on dependencies |
| `/opsx:ff` | Fast-forward: create all planning artifacts at once |
| `/opsx:apply` | Implement tasks from the change |
| `/opsx:verify` | Validate implementation matches artifacts |
| `/opsx:sync` | Merge delta specs into main specs |
| `/opsx:archive` | Archive a completed change |
| `/opsx:bulk-archive` | Archive multiple changes at once |
| `/opsx:onboard` | Guided tutorial through the complete workflow |
The default global profile is `core`. To enable expanded workflow commands, run `openspec config profile`, select workflows, then run `openspec update` in your project.
---
## Command Reference
### `/opsx:propose`
Create a new change and generate planning artifacts in one step. This is the default start command in the `core` profile.
**Syntax:**
```text
/opsx:propose [change-name-or-description]
```
**Arguments:**
| Argument | Required | Description |
|----------|----------|-------------|
| `change-name-or-description` | No | Kebab-case name or plain-language change description |
**What it does:**
- Creates `openspec/changes/<change-name>/`
- Generates artifacts needed before implementation (for `spec-driven`: proposal, specs, design, tasks)
- Stops when the change is ready for `/opsx:apply`
**Example:**
```text
You: /opsx:propose add-dark-mode
AI: Created openspec/changes/add-dark-mode/
✓ proposal.md
✓ specs/ui/spec.md
✓ design.md
✓ tasks.md
Ready for implementation. Run /opsx:apply.
```
**Tips:**
- Use this for the fastest end-to-end path
- If you want step-by-step artifact control, enable expanded workflows and use `/opsx:new` + `/opsx:continue`
---
### `/opsx:explore`
Think through ideas, investigate problems, and clarify requirements before committing to a change.
@@ -42,7 +89,7 @@ Think through ideas, investigate problems, and clarify requirements before commi
- Investigates the codebase to answer questions
- Compares options and approaches
- Creates visual diagrams to clarify thinking
- Can transition to `/opsx:new` when insights crystallize
- Can transition to `/opsx:propose` (default) or `/opsx:new` (expanded workflow) when insights crystallize
**Example:**
```text
@@ -66,7 +113,7 @@ AI: Let me investigate your current auth setup...
You: Let's go with JWT. Can we start a change for that?
AI: Ready when you are. Run /opsx:new add-jwt-auth to begin.
AI: Ready when you are. Run /opsx:propose add-jwt-auth to begin.
```
**Tips:**
@@ -79,7 +126,9 @@ AI: Ready when you are. Run /opsx:new add-jwt-auth to begin.
### `/opsx:new`
Start a new change. Creates the change folder structure and scaffolds it with the selected schema.
Start a new change scaffold. Creates the change folder and waits for you to generate artifacts with `/opsx:continue` or `/opsx:ff`.
This command is part of the expanded workflow set (not included in the default `core` profile).
**Syntax:**
```
@@ -565,13 +614,15 @@ Different AI tools use slightly different command syntax. Use the format that ma
| Tool | Syntax Example |
|------|----------------|
| Claude Code | `/opsx:new`, `/opsx:apply` |
| Cursor | `/opsx-new`, `/opsx-apply` |
| Windsurf | `/opsx-new`, `/opsx-apply` |
| Copilot | `/opsx-new`, `/opsx-apply` |
| Trae | `/openspec-new-change`, `/openspec-apply-change` |
| Claude Code | `/opsx:propose`, `/opsx:apply` |
| Cursor | `/opsx-propose`, `/opsx-apply` |
| Windsurf | `/opsx-propose`, `/opsx-apply` |
| Copilot (IDE) | `/opsx-propose`, `/opsx-apply` |
| Trae | Skill-based invocations such as `/openspec-propose`, `/openspec-apply-change` (no generated `opsx-*` command files) |
The functionality is identical regardless of syntax.
The intent is the same across tools, but how commands are surfaced can differ by integration.
> **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.
---
+73 -27
View File
@@ -7,10 +7,10 @@ This guide explains the core ideas behind OpenSpec and how they fit together. Fo
OpenSpec is built around four principles:
```
fluid not rigid — no phase gates, work on what makes sense
fluid not rigid — no phase gates, work on what makes sense
iterative not waterfall — learn as you build, refine as you go
easy not complex — lightweight setup, minimal ceremony
brownfield-first — works with existing codebases, not just greenfield
easy not complex — lightweight setup, minimal ceremony
brownfield-first — works with existing codebases, not just greenfield
```
### Why These Principles Matter
@@ -28,19 +28,19 @@ brownfield-first — works with existing codebases, not just greenfield
OpenSpec organizes your work into two main areas:
```
┌─────────────────────────────────────────────────────────────────┐
│ openspec/ │
│ │
│ ┌─────────────────────┐ ┌──────────────────────────────┐ │
│ │ specs/ │ │ changes/ │ │
│ │ │ │ │ │
│ │ Source of truth │◄─────│ Proposed modifications │ │
│ │ How your system │ merge│ Each change = one folder │ │
│ │ currently works │ │ Contains artifacts + deltas │ │
│ │ │ │ │ │
│ └─────────────────────┘ └──────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────┐
│ openspec/ │
│ │
│ ┌─────────────────────┐ ┌───────────────────────────────┐ │
│ │ specs/ │ │ changes/ │ │
│ │ │ │ │ │
│ │ Source of truth │◄─────│ Proposed modifications │ │
│ │ How your system │ merge│ Each change = one folder │ │
│ │ currently works │ │ Contains artifacts + deltas │ │
│ │ │ │ │ │
│ └─────────────────────┘ └───────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────┘
```
**Specs** are the source of truth — they describe how your system currently behaves.
@@ -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.
@@ -224,7 +270,7 @@ Delta specs describe **what's changing** relative to the current specs. See [Del
The design captures **technical approach** and **architecture decisions**.
```markdown
````markdown
# Design: Add Dark Mode
## Technical Approach
@@ -260,7 +306,7 @@ CSS Variables (applied to :root)
- `src/contexts/ThemeContext.tsx` (new)
- `src/components/ThemeToggle.tsx` (new)
- `src/styles/globals.css` (modified)
```
````
**When to update the design:**
- Implementation reveals the approach won't work
@@ -512,17 +558,17 @@ openspec/
## How It All Fits Together
```
┌─────────────────────────────────────────────────────────────────────────────┐
┌──────────────────────────────────────────────────────────────────────────────┐
│ OPENSPEC FLOW │
│ │
│ ┌────────────────┐ │
│ │ 1. START │ /opsx:new creates a change folder │
│ │ 1. START │ /opsx:propose (core) or /opsx:new (expanded) │
│ │ CHANGE │ │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ 2. CREATE │ /opsx:ff or /opsx:continue │
│ │ 2. CREATE │ /opsx:ff or /opsx:continue (expanded workflow) │
│ │ ARTIFACTS │ Creates proposal → specs → design → tasks │
│ │ │ (based on schema dependencies) │
│ └───────┬────────┘ │
@@ -541,13 +587,13 @@ openspec/
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ ┌──────────────────────────────────────────────┐ │
│ │ 5. ARCHIVE │────►│ Delta specs merge into main specs │ │
│ │ CHANGE │ │ Change folder moves to archive/ │ │
│ └────────────────┘ │ Specs are now the updated source of truth │ │
│ └──────────────────────────────────────────────┘ │
│ ┌────────────────┐ ┌──────────────────────────────────────────────┐ │
│ │ 5. ARCHIVE │────►│ Delta specs merge into main specs │ │
│ │ CHANGE │ │ Change folder moves to archive/ │ │
│ └────────────────┘ │ Specs are now the updated source of truth │ │
│ └──────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
└──────────────────────────────────────────────────────────────────────────────┘
```
**The virtuous cycle:**
+20 -40
View File
@@ -4,33 +4,22 @@ This guide explains how OpenSpec works after you've installed and initialized it
## How It Works
OpenSpec helps you and your AI coding assistant agree on what to build before any code is written. The workflow follows a simple pattern:
OpenSpec helps you and your AI coding assistant agree on what to build before any code is written.
**Default quick path (core profile):**
```text
/opsx:propose ──► /opsx:apply ──► /opsx:archive
```
┌────────────────────┐
│ Start a Change │ /opsx:new
└────────┬───────────┘
│
▼
┌────────────────────┐
│ Create Artifacts │ /opsx:ff or /opsx:continue
│ (proposal, specs, │
│ design, tasks) │
└────────┬───────────┘
│
▼
┌────────────────────┐
│ Implement Tasks │ /opsx:apply
│ (AI writes code) │
└────────┬───────────┘
│
▼
┌────────────────────┐
│ Archive & Merge │ /opsx:archive
│ Specs │
└────────────────────┘
**Expanded path (custom workflow selection):**
```text
/opsx:new ──► /opsx:ff or /opsx:continue ──► /opsx:apply ──► /opsx:verify ──► /opsx:archive
```
The default global profile is `core`, which includes `propose`, `explore`, `apply`, and `archive`. You can enable the expanded workflow commands with `openspec config profile` and then `openspec update`.
## What OpenSpec Creates
After running `openspec init`, your project has this structure:
@@ -131,23 +120,12 @@ The change folder moves to `openspec/changes/archive/` for audit history.
Let's walk through adding dark mode to an application.
### 1. Start the Change
### 1. Start the Change (Default)
```
You: /opsx:new add-dark-mode
```text
You: /opsx:propose add-dark-mode
AI: Created openspec/changes/add-dark-mode/
Ready to create: proposal
```
### 2. Create Artifacts
Use `/opsx:ff` (fast-forward) to create all planning artifacts at once:
```
You: /opsx:ff
AI: Creating artifacts for add-dark-mode...
✓ proposal.md — why we're doing this, what's changing
✓ specs/ — requirements and scenarios
✓ design.md — technical approach
@@ -155,7 +133,9 @@ AI: Creating artifacts for add-dark-mode...
Ready for implementation!
```
### 3. What Gets Created
If you've enabled the expanded workflow profile, you can also do this as two steps: `/opsx:new` then `/opsx:ff` (or `/opsx:continue` incrementally).
### 2. What Gets Created
**proposal.md** - Captures the intent:
@@ -218,7 +198,7 @@ The system SHALL allow users to choose between light and dark themes.
- [ ] 3.2 Update components to use CSS variables
```
### 4. Implement
### 3. Implement
```
You: /opsx:apply
@@ -234,7 +214,7 @@ AI: Working through tasks...
During implementation, if you discover the design needs adjustment, just update the artifact and continue.
### 5. Archive
### 4. Archive
```
You: /opsx:archive
+43 -23
View File
@@ -8,7 +8,7 @@ OPSX replaces the old phase-locked workflow with a fluid, action-based approach.
| Aspect | Legacy | OPSX |
|--------|--------|------|
| **Commands** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` | `/opsx:new`, `/opsx:continue`, `/opsx:apply`, and more |
| **Commands** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` | Default: `/opsx:propose`, `/opsx:apply`, `/opsx:archive` (expanded workflow commands optional) |
| **Workflow** | Create all artifacts at once | Create incrementally or all at once—your choice |
| **Going back** | Awkward phase gates | Natural—update any artifact anytime |
| **Customization** | Fixed structure | Schema-driven, fully hackable |
@@ -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.
@@ -84,6 +84,9 @@ Don't worry about getting it perfect. We're still learning what works best here,
Both `openspec init` and `openspec update` detect legacy files and guide you through the same cleanup process. Use whichever fits your situation:
- New installs default to profile `core` (`propose`, `explore`, `apply`, `archive`).
- Migrated installs preserve your previously installed workflows by writing a `custom` profile when needed.
### Using `openspec init`
Run this if you want to add new tools or reconfigure which tools are set up:
@@ -141,7 +144,7 @@ Run this if you just want to migrate and refresh your existing tools to the late
openspec update
```
The update command also detects and cleans up legacy artifacts, then refreshes your skills to the latest version.
The update command also detects and cleans up legacy artifacts, then refreshes generated skills/commands to match your current profile and delivery settings.
### Non-Interactive / CI Environments
@@ -275,30 +278,43 @@ The AI will help you identify what's essential vs. what can be trimmed.
## The New Commands
After migration, you have 9 OPSX commands instead of 3:
Command availability is profile-dependent:
**Default (`core` profile):**
| Command | Purpose |
|---------|---------|
| `/opsx:propose` | Create a change and generate planning artifacts in one step |
| `/opsx:explore` | Think through ideas with no structure |
| `/opsx:new` | Start a new change |
| `/opsx:continue` | Create the next artifact (one at a time) |
| `/opsx:ff` | Fast-forward—create all planning artifacts at once |
| `/opsx:apply` | Implement tasks from tasks.md |
| `/opsx:verify` | Validate implementation matches specs |
| `/opsx:sync` | Preview spec merge (optional—archive prompts if needed) |
| `/opsx:archive` | Finalize and archive the change |
**Expanded workflow (custom selection):**
| Command | Purpose |
|---------|---------|
| `/opsx:new` | Start a new change scaffold |
| `/opsx:continue` | Create the next artifact (one at a time) |
| `/opsx:ff` | Fast-forward—create planning artifacts at once |
| `/opsx:verify` | Validate implementation matches specs |
| `/opsx:sync` | Preview/spec-merge without archiving |
| `/opsx:bulk-archive` | Archive multiple changes at once |
| `/opsx:onboard` | Guided end-to-end onboarding workflow |
Enable expanded commands with `openspec config profile`, then run `openspec update`.
### Command Mapping from Legacy
| Legacy | OPSX Equivalent |
|--------|-----------------|
| `/openspec:proposal` | `/opsx:new` then `/opsx:ff` |
| `/openspec:proposal` | `/opsx:propose` (default) or `/opsx:new` then `/opsx:ff` (expanded) |
| `/openspec:apply` | `/opsx:apply` |
| `/openspec:archive` | `/opsx:archive` |
### New Capabilities
These capabilities are part of the expanded workflow command set.
**Granular artifact creation:**
```
/opsx:continue
@@ -332,14 +348,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
@@ -542,9 +558,10 @@ project/
│ └── config.yaml # NEW: Project configuration
├── .claude/
│ └── skills/ # NEW: OPSX skills
│ ├── openspec-propose/ # default core profile
│ ├── openspec-explore/
│ ├── openspec-new-change/
│ └── ...
│ ├── openspec-apply-change/
│ └── ... # expanded profile adds new/continue/ff/etc.
├── CLAUDE.md # OpenSpec markers removed, your content preserved
└── AGENTS.md # OpenSpec markers removed, your content preserved
```
@@ -558,12 +575,15 @@ project/
### Command Cheatsheet
```
/opsx:new Start a change
/opsx:continue Create next artifact
/opsx:ff Create all planning artifacts
```text
/opsx:propose Start quickly (default core profile)
/opsx:apply Implement tasks
/opsx:archive Finish and archive
# Expanded workflow (if enabled):
/opsx:new Scaffold a change
/opsx:continue Create next artifact
/opsx:ff Create planning artifacts
```
---
+24 -9
View File
@@ -65,6 +65,8 @@ openspec init
This creates skills in `.claude/skills/` (or equivalent) that AI coding assistants auto-detect.
By default, OpenSpec uses the `core` workflow profile (`propose`, `explore`, `apply`, `archive`). If you want the expanded workflow commands (`new`, `continue`, `ff`, `verify`, `sync`, `bulk-archive`, `onboard`), configure them with `openspec config profile` and apply with `openspec update`.
During setup, you'll be prompted to create a **project config** (`openspec/config.yaml`). This is optional but recommended.
## Project Configuration
@@ -155,13 +157,17 @@ rules:
| Command | What it does |
|---------|--------------|
| `/opsx:propose` | Create a change and generate planning artifacts in one step (default quick path) |
| `/opsx:explore` | Think through ideas, investigate problems, clarify requirements |
| `/opsx:new` | Start a new change |
| `/opsx:continue` | Create the next artifact (based on what's ready) |
| `/opsx:ff` | Fast-forward — create all planning artifacts at once |
| `/opsx:new` | Start a new change scaffold (expanded workflow) |
| `/opsx:continue` | Create the next artifact (expanded workflow) |
| `/opsx:ff` | Fast-forward planning artifacts (expanded workflow) |
| `/opsx:apply` | Implement tasks, updating artifacts as needed |
| `/opsx:sync` | Sync delta specs to main (optional—archive prompts if needed) |
| `/opsx:verify` | Validate implementation against artifacts (expanded workflow) |
| `/opsx:sync` | Sync delta specs to main (expanded workflow, optional) |
| `/opsx:archive` | Archive when done |
| `/opsx:bulk-archive` | Archive multiple completed changes (expanded workflow) |
| `/opsx:onboard` | Guided walkthrough of an end-to-end change (expanded workflow) |
## Usage
@@ -169,13 +175,21 @@ rules:
```
/opsx:explore
```
Think through ideas, investigate problems, compare options. No structure required - just a thinking partner. When insights crystallize, transition to `/opsx:new` or `/opsx:ff`.
Think through ideas, investigate problems, compare options. No structure required - just a thinking partner. When insights crystallize, transition to `/opsx:propose` (default) or `/opsx:new`/`/opsx:ff` (expanded).
### Start a new change
```
/opsx:new
/opsx:propose
```
Creates the change and generates planning artifacts needed before implementation.
If you've enabled expanded workflows, you can instead use:
```text
/opsx:new # scaffold only
/opsx:continue # create one artifact at a time
/opsx:ff # create all planning artifacts at once
```
You'll be asked what you want to build and which workflow schema to use.
### Create artifacts
```
@@ -299,6 +313,7 @@ Think of it like git branches:
## Architecture Deep Dive
This section explains how OPSX works under the hood and how it compares to the legacy workflow.
Examples in this section use the expanded command set (`new`, `continue`, etc.); default `core` users can map the same flow to `propose → apply → archive`.
### Philosophy: Phases vs Actions
@@ -356,7 +371,7 @@ This section explains how OPSX works under the hood and how it compares to the l
│ Hardcoded Templates (TypeScript strings) │
│ │ │
│ ▼ │
│ Configurators (18+ classes, one per editor) │
│ Tool-specific configurators/adapters │
│ │ │
│ ▼ │
│ Generated Command Files (.claude/commands/openspec/*.md) │
@@ -604,7 +619,7 @@ artifacts:
| **State** | Phase-based mental model | Filesystem existence |
| **Customization** | Edit source, rebuild | Create schema.yaml |
| **Iteration** | Phase-locked | Fluid, edit anything |
| **Editor Support** | 18+ configurator classes | Single skills directory |
| **Editor Support** | Tool-specific configurator/adapters | Single skills directory |
## Schemas
+70 -49
View File
@@ -1,46 +1,61 @@
# Supported Tools
OpenSpec works with 20+ AI coding assistants. When you run `openspec init`, you'll be prompted to select which tools you use, and OpenSpec will configure the appropriate integrations.
OpenSpec works with many AI coding assistants. When you run `openspec init`, OpenSpec configures selected tools using your active profile/workflow selection and delivery mode.
## How It Works
For each tool you select, OpenSpec installs:
For each selected tool, OpenSpec can install:
1. **Skills** — Reusable instruction files that power the `/opsx:*` workflow commands
2. **Commands** — Tool-specific slash command bindings
1. **Skills** (if delivery includes skills): `.../skills/openspec-*/SKILL.md`
2. **Commands** (if delivery includes commands): tool-specific `opsx-*` command files
By default, OpenSpec uses the `core` profile, which includes:
- `propose`
- `explore`
- `apply`
- `archive`
You can enable expanded workflows (`new`, `continue`, `ff`, `verify`, `sync`, `bulk-archive`, `onboard`) via `openspec config profile`, then run `openspec update`.
## Tool Directory Reference
| Tool | Skills Location | Commands Location |
|------|-----------------|-------------------|
| Amazon Q Developer | `.amazonq/skills/` | `.amazonq/prompts/` |
| Antigravity | `.agent/skills/` | `.agent/workflows/` |
| Auggie (Augment CLI) | `.augment/skills/` | `.augment/commands/` |
| Claude Code | `.claude/skills/` | `.claude/commands/opsx/` |
| Cline | `.cline/skills/` | `.clinerules/workflows/` |
| CodeBuddy | `.codebuddy/skills/` | `.codebuddy/commands/opsx/` |
| 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/` |
| iFlow | `.iflow/skills/` | `.iflow/commands/` |
| Kilo Code | `.kilocode/skills/` | `.kilocode/workflows/` |
| OpenCode | `.opencode/skills/` | `.opencode/command/` |
| 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/workflows/` |
| Tool (ID) | Skills path pattern | Command path pattern |
|-----------|---------------------|----------------------|
| Amazon Q Developer (`amazon-q`) | `.amazonq/skills/openspec-*/SKILL.md` | `.amazonq/prompts/opsx-<id>.md` |
| Antigravity (`antigravity`) | `.agent/skills/openspec-*/SKILL.md` | `.agent/workflows/opsx-<id>.md` |
| Auggie (`auggie`) | `.augment/skills/openspec-*/SKILL.md` | `.augment/commands/opsx-<id>.md` |
| IBM Bob Shell (`bob`) | `.bob/skills/openspec-*/SKILL.md` | `.bob/commands/opsx-<id>.md` |
| Claude Code (`claude`) | `.claude/skills/openspec-*/SKILL.md` | `.claude/commands/opsx/<id>.md` |
| Cline (`cline`) | `.cline/skills/openspec-*/SKILL.md` | `.clinerules/workflows/opsx-<id>.md` |
| CodeBuddy (`codebuddy`) | `.codebuddy/skills/openspec-*/SKILL.md` | `.codebuddy/commands/opsx/<id>.md` |
| Codex (`codex`) | `.codex/skills/openspec-*/SKILL.md` | `$CODEX_HOME/prompts/opsx-<id>.md`\* |
| ForgeCode (`forgecode`) | `.forge/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use skill-based `/openspec-*` invocations) |
| Continue (`continue`) | `.continue/skills/openspec-*/SKILL.md` | `.continue/prompts/opsx-<id>.prompt` |
| CoStrict (`costrict`) | `.cospec/skills/openspec-*/SKILL.md` | `.cospec/openspec/commands/opsx-<id>.md` |
| Crush (`crush`) | `.crush/skills/openspec-*/SKILL.md` | `.crush/commands/opsx/<id>.md` |
| Cursor (`cursor`) | `.cursor/skills/openspec-*/SKILL.md` | `.cursor/commands/opsx-<id>.md` |
| Factory Droid (`factory`) | `.factory/skills/openspec-*/SKILL.md` | `.factory/commands/opsx-<id>.md` |
| Gemini CLI (`gemini`) | `.gemini/skills/openspec-*/SKILL.md` | `.gemini/commands/opsx/<id>.toml` |
| GitHub Copilot (`github-copilot`) | `.github/skills/openspec-*/SKILL.md` | `.github/prompts/opsx-<id>.prompt.md`\*\* |
| iFlow (`iflow`) | `.iflow/skills/openspec-*/SKILL.md` | `.iflow/commands/opsx-<id>.md` |
| Junie (`junie`) | `.junie/skills/openspec-*/SKILL.md` | `.junie/commands/opsx-<id>.md` |
| Kilo Code (`kilocode`) | `.kilocode/skills/openspec-*/SKILL.md` | `.kilocode/workflows/opsx-<id>.md` |
| Kiro (`kiro`) | `.kiro/skills/openspec-*/SKILL.md` | `.kiro/prompts/opsx-<id>.prompt.md` |
| OpenCode (`opencode`) | `.opencode/skills/openspec-*/SKILL.md` | `.opencode/commands/opsx-<id>.md` |
| Pi (`pi`) | `.pi/skills/openspec-*/SKILL.md` | `.pi/prompts/opsx-<id>.md` |
| Qoder (`qoder`) | `.qoder/skills/openspec-*/SKILL.md` | `.qoder/commands/opsx/<id>.md` |
| Qwen Code (`qwen`) | `.qwen/skills/openspec-*/SKILL.md` | `.qwen/commands/opsx-<id>.toml` |
| RooCode (`roocode`) | `.roo/skills/openspec-*/SKILL.md` | `.roo/commands/opsx-<id>.md` |
| Trae (`trae`) | `.trae/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use skill-based `/openspec-*` invocations) |
| Windsurf (`windsurf`) | `.windsurf/skills/openspec-*/SKILL.md` | `.windsurf/workflows/opsx-<id>.md` |
\* Codex commands are installed to the global home directory (`~/.codex/prompts/` or `$CODEX_HOME/prompts/`), not the project directory.
\* Codex commands are installed in the global Codex home (`$CODEX_HOME/prompts/` if set, otherwise `~/.codex/prompts/`), not your project directory.
\*\* GitHub Copilot prompt files are recognized as custom slash commands in IDE extensions (VS Code, JetBrains, Visual Studio). Copilot CLI does not currently consume `.github/prompts/*.prompt.md` directly.
## Non-Interactive Setup
For CI/CD or scripted setup, use the `--tools` flag:
For CI/CD or scripted setup, use `--tools` (and optionally `--profile`):
```bash
# Configure specific tools
@@ -51,34 +66,40 @@ openspec init --tools all
# Skip tool configuration
openspec init --tools none
# Override profile for this init run
openspec init --profile core
```
**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 (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `bob`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `forgecode`, `gemini`, `github-copilot`, `iflow`, `junie`, `kilocode`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
## What Gets Installed
## Workflow-Dependent Installation
For each tool, OpenSpec generates 10 skill files that power the OPSX workflow:
OpenSpec installs workflow artifacts based on selected workflows:
| Skill | Purpose |
|-------|---------|
| `openspec-explore` | Thinking partner for exploring ideas |
| `openspec-new-change` | Start a new change |
| `openspec-continue-change` | Create the next artifact |
| `openspec-ff-change` | Fast-forward through all planning artifacts |
| `openspec-apply-change` | Implement tasks |
| `openspec-verify-change` | Verify implementation completeness |
| `openspec-sync-specs` | Sync delta specs to main (optional—archive prompts if needed) |
| `openspec-archive-change` | Archive a completed change |
| `openspec-bulk-archive-change` | Archive multiple changes at once |
| `openspec-onboard` | Guided onboarding through a complete workflow cycle |
- **Core profile (default):** `propose`, `explore`, `apply`, `archive`
- **Custom selection:** any subset of all workflow IDs:
`propose`, `explore`, `new`, `continue`, `apply`, `ff`, `sync`, `archive`, `bulk-archive`, `verify`, `onboard`
These skills are invoked via slash commands like `/opsx:new`, `/opsx:apply`, etc. See [Commands](commands.md) for the full list.
In other words, skill/command counts are profile-dependent and delivery-dependent, not fixed.
## Adding a New Tool
## Generated Skill Names
Want to add support for another AI coding assistant? Check out the [command adapter pattern](../CONTRIBUTING.md) or open an issue on GitHub.
When selected by profile/workflow config, OpenSpec generates these skills:
---
- `openspec-propose`
- `openspec-explore`
- `openspec-new-change`
- `openspec-continue-change`
- `openspec-apply-change`
- `openspec-ff-change`
- `openspec-sync-specs`
- `openspec-archive-change`
- `openspec-bulk-archive-change`
- `openspec-verify-change`
- `openspec-onboard`
See [Commands](commands.md) for command behavior and [CLI](cli.md) for `init`/`update` options.
## Related
+33 -7
View File
@@ -28,7 +28,32 @@ OPSX (fluid actions):
> **Customization:** OPSX workflows are driven by schemas that define artifact sequences. See [Customization](customization.md) for details on creating custom schemas.
## Workflow Patterns
## Two Modes
### Default Quick Path (`core` profile)
New installs default to `core`, which provides:
- `/opsx:propose`
- `/opsx:explore`
- `/opsx:apply`
- `/opsx:archive`
Typical flow:
```text
/opsx:propose ──► /opsx:apply ──► /opsx:archive
```
### Expanded/Full Workflow (custom selection)
If you want explicit scaffold-and-build commands (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:sync`, `/opsx:bulk-archive`, `/opsx:onboard`), enable them with:
```bash
openspec config profile
openspec update
```
## Workflow Patterns (Expanded Mode)
### Quick Feature
@@ -408,15 +433,16 @@ For full command details and options, see [Commands](commands.md).
| Command | Purpose | When to Use |
|---------|---------|-------------|
| `/opsx:propose` | Create change + planning artifacts | Fast default path (`core` profile) |
| `/opsx:explore` | Think through ideas | Unclear requirements, investigation |
| `/opsx:new` | Start a change | Beginning any new work |
| `/opsx:continue` | Create next artifact | Step-by-step artifact creation |
| `/opsx:ff` | Create all planning artifacts | Clear scope, ready to build |
| `/opsx:new` | Start a change scaffold | Expanded mode, explicit artifact control |
| `/opsx:continue` | Create next artifact | Expanded mode, step-by-step artifact creation |
| `/opsx:ff` | Create all planning artifacts | Expanded mode, clear scope |
| `/opsx:apply` | Implement tasks | Ready to write code |
| `/opsx:verify` | Validate implementation | Before archiving, catch mismatches |
| `/opsx:sync` | Merge delta specs | Optional—archive prompts if needed |
| `/opsx:verify` | Validate implementation | Expanded mode, before archiving |
| `/opsx:sync` | Merge delta specs | Expanded mode, optional |
| `/opsx:archive` | Complete the change | All work finished |
| `/opsx:bulk-archive` | Archive multiple changes | Parallel work, batch completion |
| `/opsx:bulk-archive` | Archive multiple changes | Expanded mode, parallel work |
## Next Steps
@@ -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
@@ -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-02-25
@@ -0,0 +1,48 @@
## Context
The OpenCode adapter in `src/core/command-generation/adapters/opencode.ts` currently generates command files at `.opencode/command/opsx-<id>.md` (singular `command`). OpenCode's official documentation uses `.opencode/commands/` (plural), and every other adapter in the codebase follows the plural convention for commands directories. The legacy cleanup module in `src/core/legacy-cleanup.ts` also references the singular form for detecting old artifacts.
## Goals / Non-Goals
**Goals:**
- Align the OpenCode adapter path with OpenCode's official `.opencode/commands/` convention
- Add the old singular path `.opencode/command/` to legacy cleanup so existing installations are properly cleaned
- Update documentation to reflect the corrected path
- Update test assertions to match the new path
**Non-Goals:**
- Changing the OpenCode skill path (`.opencode/skills/`) — already correct
- Modifying any other adapter's directory structure
- Adding migration prompts or interactive upgrade flows
## Decisions
### 1. Direct path rename in adapter
**Decision:** Change `path.join('.opencode', 'command', ...)` to `path.join('.opencode', 'commands', ...)` in the adapter's `getFilePath` method.
**Rationale:** This is a single-line change that aligns with the established pattern across all other adapters. No abstraction or indirection needed.
**Alternatives considered:**
- Add a configuration option for the directory name — rejected as over-engineering for a bug fix
- Keep singular and add plural as alias — rejected as it creates ambiguity about which is canonical
### 2. Legacy cleanup via existing constant map
**Decision:** Update the `LEGACY_SLASH_COMMAND_PATHS` entry for `'opencode'` from `'.opencode/command/openspec-*.md'` to `'.opencode/command/opsx-*.md'` (the old singular path becomes the legacy pattern) and ensure the new path is handled by the current command generation pipeline.
**Rationale:** The existing legacy cleanup infrastructure uses `LEGACY_SLASH_COMMAND_PATHS` as an explicit lookup. The old singular-path pattern already matches the legacy format (`openspec-*` prefix from the old SlashCommandRegistry era). The current command generation uses the `opsx-*` prefix, so we also need to add a legacy pattern for `opsx-*` files in the old singular directory.
**Alternatives considered:**
- Add a separate migration script — rejected; the existing legacy cleanup mechanism handles this scenario
### 3. Documentation update
**Decision:** Update the `docs/supported-tools.md` table entry for OpenCode from `.opencode/command/opsx-<id>.md` to `.opencode/commands/opsx-<id>.md`.
**Rationale:** Documentation must match the actual generated paths.
## Risks / Trade-offs
- **[Existing installations have files at old path]** → Mitigated by legacy cleanup detecting `.opencode/command/` artifacts. On next `openspec init`, old files are cleaned up and new files written to `.opencode/commands/`.
- **[Users referencing old path in custom scripts]** → Low risk. The old path was incorrect per OpenCode's specification, so custom references were already misaligned.
@@ -0,0 +1,26 @@
## Why
The OpenCode adapter uses `.opencode/command/` (singular) for its commands directory, but OpenCode's official documentation specifies `.opencode/commands/` (plural). Every other adapter in the codebase also uses plural directory names (`.claude/commands/`, `.cursor/commands/`, `.factory/commands/`, etc.). This inconsistency was introduced in Oct 2025 without documented rationale. Fixes [#748](https://github.com/Fission-AI/OpenSpec/issues/748).
## What Changes
- OpenCode adapter path changes from `.opencode/command/` to `.opencode/commands/`
- Legacy cleanup adds `.opencode/command/` (old singular path) for backward compatibility
- Documentation updated to reflect the new plural path
## Capabilities
### New Capabilities
_None._
### Modified Capabilities
- `command-generation`: OpenCode adapter path changes from singular `command/` to plural `commands/` to match OpenCode's official directory convention
## Impact
- `src/core/command-generation/adapters/opencode.ts` — adapter path
- `src/core/legacy-cleanup.ts` — legacy cleanup pattern + add old singular path
- `docs/supported-tools.md` — documentation table
- `test/core/command-generation/adapters.test.ts` — test assertion
@@ -0,0 +1,63 @@
## MODIFIED Requirements
### Requirement: ToolCommandAdapter interface
The system SHALL define a `ToolCommandAdapter` interface for per-tool formatting.
#### Scenario: Adapter interface structure
- **WHEN** implementing a tool adapter
- **THEN** `ToolCommandAdapter` SHALL require:
- `toolId`: string identifier matching `AIToolOption.value`
- `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
- **WHEN** formatting a command for Claude Code
- **THEN** the adapter SHALL output YAML frontmatter with `name`, `description`, `category`, `tags` fields
- **AND** file path SHALL follow pattern `.claude/commands/opsx/<id>.md`
#### Scenario: Cursor adapter formatting
- **WHEN** formatting a command for Cursor
- **THEN** the adapter SHALL output YAML frontmatter with `name` as `/opsx-<id>`, `id`, `category`, `description` fields
- **AND** file path SHALL follow pattern `.cursor/commands/opsx-<id>.md`
#### Scenario: Windsurf adapter 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/workflows/opsx-<id>.md`
#### Scenario: OpenCode adapter formatting
- **WHEN** formatting a command for OpenCode
- **THEN** the adapter SHALL output YAML frontmatter with `description` field
- **AND** file path SHALL follow pattern `.opencode/commands/opsx-<id>.md` using `path.join('.opencode', 'commands', ...)` for cross-platform compatibility
- **AND** the adapter SHALL transform colon-based command references (`/opsx:name`) to hyphen-based (`/opsx-name`) in the body
## ADDED Requirements
### Requirement: Legacy cleanup for renamed OpenCode command directory
The legacy cleanup module SHALL detect and remove old OpenCode command files from the previous singular `.opencode/command/` directory path.
#### Scenario: Detect old singular-path OpenCode command files
- **WHEN** running legacy artifact detection on a project with files matching `.opencode/command/opsx-*.md` or `.opencode/command/openspec-*.md`
- **THEN** the system SHALL include those files in the legacy slash command files list via `LEGACY_SLASH_COMMAND_PATHS`
- **AND** `LegacySlashCommandPattern.pattern` SHALL accept `string | string[]` to support multiple glob patterns per tool
#### Scenario: Clean up old OpenCode command files on init
- **WHEN** a user runs `openspec init` in a project with old `.opencode/command/` artifacts
- **THEN** the system SHALL remove the old files
- **AND** generate new command files at `.opencode/commands/`
#### Scenario: Auto-cleanup legacy artifacts in non-interactive mode
- **WHEN** a user runs `openspec init` in non-interactive mode (e.g., CI) and legacy artifacts are detected
- **THEN** the system SHALL auto-cleanup legacy artifacts without requiring `--force`
- **AND** legacy slash command files (100% OpenSpec-managed) SHALL be removed
- **AND** config file cleanup SHALL only remove OpenSpec markers (never delete user files)
@@ -0,0 +1,19 @@
## 1. Adapter Fix
- [x] 1.1 Update `src/core/command-generation/adapters/opencode.ts`: change `path.join('.opencode', 'command', ...)` to `path.join('.opencode', 'commands', ...)` and update the JSDoc comment
## 2. Legacy Cleanup
- [x] 2.1 Update `src/core/legacy-cleanup.ts`: update the `'opencode'` entry in `LEGACY_SLASH_COMMAND_PATHS` to detect both `opsx-*.md` and `openspec-*.md` patterns at `.opencode/command/` for backward compatibility
## 3. Documentation
- [x] 3.1 Update `docs/supported-tools.md`: change OpenCode command path from `.opencode/command/opsx-<id>.md` to `.opencode/commands/opsx-<id>.md`
## 4. Tests
- [x] 4.1 Update `test/core/command-generation/adapters.test.ts`: change the OpenCode file path assertion from `path.join('.opencode', 'command', 'opsx-explore.md')` to `path.join('.opencode', 'commands', 'opsx-explore.md')`
## 5. Changeset
- [x] 5.1 Create a changeset file (`.changeset/fix-opencode-commands-directory.md`) with a patch bump describing the path fix
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-25
@@ -0,0 +1,38 @@
## Context
`statusCommand` in `src/commands/workflow/status.ts` calls `validateChangeExists()` from `shared.ts` as its first operation. When no `--change` option is provided and no change directories exist, `validateChangeExists` throws: `No changes found. Create one with: openspec new change <name>`. This error propagates up as a fatal CLI error (non-zero exit code).
This is correct behavior for commands like `apply` and `show` that require a change to operate on. However, `status` is an informational command — it should report the current state, even when that state is "no changes exist."
The error surfaces during onboarding (issue #714) when AI agents call `openspec status` before any change has been created.
## Goals / Non-Goals
**Goals:**
- Make `openspec status` exit with code 0 and a friendly message when no changes exist
- Support both text and JSON output modes for the no-changes case
- Keep all other commands' validation behavior unchanged
**Non-Goals:**
- Changing the behavior of `validateChangeExists` (keep it strict for all consumers; only extract its internal helper)
- Changing the onboard template or skill instructions
- Handling the case where `--change` is provided but the specific change doesn't exist (this should remain an error)
## Decisions
### Extract `getAvailableChanges` and check before validation
**Rationale**: Extract the private `getAvailableChanges` closure from `validateChangeExists` into a public exported function in `shared.ts`. Then, in `statusCommand`, call `getAvailableChanges` *before* `validateChangeExists` to detect the no-changes case early and handle it gracefully. This avoids using try/catch for control flow and eliminates any coupling to error message strings.
**Alternative considered**: Catching the error from `validateChangeExists` by matching `error.message.startsWith('No changes found')`. Rejected because string coupling is fragile — if the error message changes, the catch silently stops working.
**Alternative considered**: Adding a `throwOnEmpty` parameter to `validateChangeExists`. Rejected because it adds complexity to a shared function for a single consumer's needs and mixes UX concerns into a validation utility.
### Keep `validateChangeExists` strict
**Rationale**: `validateChangeExists` remains unchanged in behavior — it still throws for all error cases. The graceful handling lives entirely in `statusCommand`, which is the appropriate layer for UX decisions. Other commands (`apply`, `show`, `instructions`) are unaffected.
## Risks / Trade-offs
- [Risk] Extra filesystem read when no `--change` is provided and changes *do* exist (`getAvailableChanges` is called first, then `validateChangeExists` performs its own read) → Mitigation: `statusCommand` returns early before reaching `validateChangeExists` when no changes exist, so the double-read only occurs when changes are present — minimal overhead.
- [Risk] Other commands may also benefit from graceful no-changes handling in the future → Mitigation: `getAvailableChanges` is now public and reusable, making it easy to apply the same pattern elsewhere.
@@ -0,0 +1,25 @@
## Why
When `openspec status` is called without `--change` and no changes exist (e.g., during onboarding on a freshly initialized project), the CLI throws a fatal error: `No changes found. Create one with: openspec new change <name>`. This breaks the onboarding flow because AI agents may call `openspec status` before any change has been created, causing the agent to halt or report failure. Fixes [#714](https://github.com/Fission-AI/OpenSpec/issues/714).
## What Changes
- `openspec status` will exit gracefully (code 0) with a friendly message when no changes exist, instead of throwing a fatal error
- `openspec status --json` will return a valid JSON object with an empty changes array when no changes exist
- Other commands (`apply`, `show`, etc.) retain their current strict validation behavior
## Capabilities
### New Capabilities
- `graceful-status-empty`: Graceful handling of `openspec status` when no changes exist, covering both text and JSON output modes
### Modified Capabilities
_None — `validateChangeExists` was internally refactored to delegate to the newly exported `getAvailableChanges`, but its behavior and public contract are unchanged. Other consumers are unaffected._
## Impact
- `src/commands/workflow/shared.ts` — extract `getAvailableChanges` as a public function (validation behavior unchanged)
- `src/commands/workflow/status.ts` — check for available changes before validation, handle empty case gracefully
- Tests for the status command need to cover the new graceful behavior
@@ -0,0 +1,27 @@
## ADDED Requirements
### Requirement: Status command exits gracefully when no changes exist
The `statusCommand` function SHALL check for available changes via `getAvailableChanges` before calling `validateChangeExists`. When no `--change` option is provided and no change directories exist, it SHALL print a friendly informational message and exit with code 0, instead of reaching `validateChangeExists` and propagating a fatal error.
#### Scenario: No changes exist, text mode
- **WHEN** user runs `openspec status` without `--change` and no change directories exist under `openspec/changes/`
- **THEN** the CLI prints `No active changes. Create one with: openspec new change <name>` to stdout and exits with code 0
#### Scenario: No changes exist, JSON mode
- **WHEN** user runs `openspec status --json` without `--change` and no change directories exist
- **THEN** the CLI outputs `{"changes":[],"message":"No active changes."}` as valid JSON to stdout and exits with code 0
### Requirement: Existing status validation behavior is preserved
Other error paths in `validateChangeExists` that apply to the status command SHALL continue to throw errors as before. Commands other than `status` that use `validateChangeExists` SHALL NOT be affected.
#### Scenario: Changes exist but --change not specified
- **WHEN** user runs `openspec status` without `--change` and one or more change directories exist
- **THEN** the CLI throws an error listing available changes with the message `Missing required option --change. Available changes: ...`
#### Scenario: Specified change does not exist
- **WHEN** user runs `openspec status --change non-existent`
- **THEN** the CLI throws an error with message `Change 'non-existent' not found`
#### Scenario: Other commands unaffected
- **WHEN** user runs `openspec show` or `openspec instructions` without `--change` and no changes exist
- **THEN** the CLI throws the original `No changes found` error (no behavior change)
@@ -0,0 +1,16 @@
## 1. Implementation
- [x] 1.1 Extract `getAvailableChanges` in `shared.ts` and use it in `statusCommand` to check for changes before calling `validateChangeExists`
- [x] 1.2 In text mode: print `No active changes. Create one with: openspec new change <name>` and return (exit 0)
- [x] 1.3 In JSON mode: output `{"changes":[],"message":"No active changes."}` and return (exit 0)
## 2. Tests
- [x] 2.1 Add test: `openspec status` with no changes exits gracefully with friendly message (text mode)
- [x] 2.2 Add test: `openspec status --json` with no changes returns valid JSON with empty changes array
- [x] 2.3 Verify existing behavior: `openspec status` without `--change` when changes exist still throws missing option error
- [x] 2.4 Verify cross-platform: tests use `path.join()` for any path assertions
## 3. Release
- [x] 3.1 Add changeset describing the fix
@@ -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,177 @@
## 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 synchronized to active profile
The update command SHALL remove workflow files that are no longer selected in the current profile.
#### Scenario: Deselected 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 or deselected workflows via `openspec config profile`)
- **THEN** the system SHALL delete skill and command workflow files for deselected workflows (respecting active delivery mode)
- **THEN** the system SHALL keep only workflows currently selected in profile
#### 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

Some files were not shown because too many files have changed in this diff Show More