Repository: Fission-AI/OpenSpec Branch: main Commit: afdca0d5dab1 Files: 644 Total size: 2.9 MB Directory structure: gitextract_ovuhyth0/ ├── .actrc ├── .changeset/ │ ├── README.md │ ├── config.json │ ├── fix-opencode-commands-directory.md │ └── graceful-status-no-changes.md ├── .coderabbit.yaml ├── .devcontainer/ │ ├── README.md │ └── devcontainer.json ├── .github/ │ ├── CODEOWNERS │ └── workflows/ │ ├── README.md │ ├── ci.yml │ └── release-prepare.yml ├── .gitignore ├── AGENTS.md ├── CHANGELOG.md ├── LICENSE ├── MAINTAINERS.md ├── README.md ├── README_OLD.md ├── bin/ │ └── openspec.js ├── build.js ├── docs/ │ ├── cli.md │ ├── commands.md │ ├── concepts.md │ ├── customization.md │ ├── getting-started.md │ ├── installation.md │ ├── migration-guide.md │ ├── multi-language.md │ ├── opsx.md │ ├── supported-tools.md │ └── workflows.md ├── eslint.config.js ├── flake.nix ├── openspec/ │ ├── changes/ │ │ ├── IMPLEMENTATION_ORDER.md │ │ ├── add-artifact-regeneration-support/ │ │ │ └── proposal.md │ │ ├── add-change-stacking-awareness/ │ │ │ ├── .openspec.yaml │ │ │ ├── proposal.md │ │ │ ├── specs/ │ │ │ │ ├── change-creation/ │ │ │ │ │ └── spec.md │ │ │ │ ├── change-stacking-workflow/ │ │ │ │ │ └── spec.md │ │ │ │ ├── cli-change/ │ │ │ │ │ └── spec.md │ │ │ │ └── openspec-conventions/ │ │ │ │ └── spec.md │ │ │ └── tasks.md │ │ ├── add-global-install-scope/ │ │ │ ├── .openspec.yaml │ │ │ ├── design.md │ │ │ ├── proposal.md │ │ │ ├── specs/ │ │ │ │ ├── ai-tool-paths/ │ │ │ │ │ └── spec.md │ │ │ │ ├── cli-config/ │ │ │ │ │ └── spec.md │ │ │ │ ├── cli-init/ │ │ │ │ │ └── spec.md │ │ │ │ ├── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ ├── command-generation/ │ │ │ │ │ └── spec.md │ │ │ │ ├── global-config/ │ │ │ │ │ └── spec.md │ │ │ │ └── installation-scope/ │ │ │ │ └── spec.md │ │ │ └── tasks.md │ │ ├── add-qa-smoke-harness/ │ │ │ ├── .openspec.yaml │ │ │ ├── proposal.md │ │ │ └── specs/ │ │ │ └── developer-qa-workflow/ │ │ │ └── spec.md │ │ ├── add-tool-command-surface-capabilities/ │ │ │ ├── .openspec.yaml │ │ │ ├── proposal.md │ │ │ ├── specs/ │ │ │ │ ├── cli-init/ │ │ │ │ │ └── spec.md │ │ │ │ └── cli-update/ │ │ │ │ └── spec.md │ │ │ └── tasks.md │ │ ├── archive/ │ │ │ ├── 2025-01-11-add-update-command/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-01-13-add-list-command/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-list/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-05-initialize-typescript-project/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-06-add-init-command/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-init/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-06-adopt-future-state-storage/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── openspec-conventions/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-11-add-complexity-guidelines/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── openspec-docs/ │ │ │ │ │ └── README.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-13-add-archive-command/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-archive/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-13-add-diff-command/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-diff/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-19-add-change-commands/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-change/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-list/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-19-add-interactive-show-command/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-change/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ ├── cli-show/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-spec/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-19-add-skip-specs-archive-option/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-archive/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-19-add-spec-commands/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-spec/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-19-add-zod-validation/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-archive/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-diff/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-19-adopt-delta-based-changes/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-archive/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ ├── cli-diff/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── openspec-conventions/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-19-adopt-verb-noun-cli-structure/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-list/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── openspec-conventions/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-19-bulk-validation-interactive-selection/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-change/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ ├── cli-spec/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-validate/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-19-fix-update-tool-selection/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-19-improve-validate-error-messages/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-validate/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-08-19-structured-spec-format/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── openspec-conventions/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-12-add-view-dashboard-command/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-view/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-29-add-agents-md-config/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-29-add-multi-agent-init/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-init/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-29-add-slash-command-support/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-29-improve-cli-e2e-plan/ │ │ │ │ ├── proposal.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-29-improve-deterministic-tests/ │ │ │ │ ├── proposal.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-29-improve-init-onboarding/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-init/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-29-remove-diff-command/ │ │ │ │ ├── proposal.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-29-sort-active-changes-by-progress/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-view/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-29-update-agent-file-name/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ ├── cli-update/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── openspec-conventions/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-29-update-agent-instructions/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-09-29-update-markdown-parser-crlf/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-validate/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-14-add-codex-slash-command-support/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-14-add-github-copilot-prompts/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-14-add-kilocode-workflows/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-14-add-non-interactive-init-options/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-init/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-14-add-windsurf-workflows/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-14-enhance-validation-error-messages/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-validate/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-14-improve-agent-instruction-usability/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── docs-agent-instructions/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-14-slim-root-agents-file/ │ │ │ │ ├── proposal.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-14-update-cli-init-enter-selection/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-init/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-14-update-cli-init-root-agents/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-14-update-release-automation/ │ │ │ │ ├── proposal.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-22-add-archive-command-arguments/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-22-add-cline-support/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-init/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-22-add-crush-support/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-init/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-10-22-add-factory-slash-commands/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-11-06-add-shell-completions/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-completion/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-12-20-add-global-config-dir/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── global-config/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-12-21-add-config-command/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-config/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-12-23-extend-shell-completions/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-completion/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-12-24-add-artifact-graph-core/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── artifact-graph/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-12-25-add-change-manager/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── change-creation/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-12-28-add-artifact-workflow-cli/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-artifact-workflow/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-12-28-add-instruction-loader/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── instruction-loader/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-12-28-restructure-schema-directories/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── artifact-graph/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-12-29-unify-change-state-model/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-artifact-workflow/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-view/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-12-30-add-antigravity-support/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2025-12-30-fix-cline-workflows-implementation/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-01-06-add-agent-schema-selection/ │ │ │ │ ├── proposal.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-01-06-add-per-change-schema-metadata/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-artifact-workflow/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-01-06-add-specs-apply-command/ │ │ │ │ ├── .openspec.yaml │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── specs-sync-skill/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-01-06-make-apply-instructions-schema-aware/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-artifact-workflow/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-01-06-opsx-archive-command/ │ │ │ │ ├── .openspec.yaml │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── opsx-archive-skill/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-01-07-add-nix-flake-support/ │ │ │ │ ├── .openspec.yaml │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── nix-flake-support/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-01-09-add-flake-update-script/ │ │ │ │ ├── .openspec.yaml │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── flake-update-script/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-01-09-add-posthog-analytics/ │ │ │ │ ├── .openspec.yaml │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── global-config/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── telemetry/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-01-09-fix-codebuddy-frontmatter-fields/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-01-15-add-nix-ci-validation/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── ci-nix-validation/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-01-30-opencode-command-references/ │ │ │ │ ├── .openspec.yaml │ │ │ │ ├── README.md │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── no-changes.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-02-17-add-feedback-command/ │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── cli-feedback/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-02-17-add-opsx-onboard-skill/ │ │ │ │ ├── .openspec.yaml │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── opsx-onboard-skill/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-02-17-add-verify-skill/ │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── opsx-verify-skill/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-02-17-merge-init-experimental/ │ │ │ │ ├── .openspec.yaml │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── cli-init/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── legacy-cleanup/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-02-17-multi-provider-skill-generation/ │ │ │ │ ├── .openspec.yaml │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── ai-tool-paths/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ ├── cli-artifact-workflow/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── command-generation/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-02-17-project-config/ │ │ │ │ ├── .openspec.yaml │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ ├── config-loading/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ ├── context-injection/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ ├── rules-injection/ │ │ │ │ │ │ └── spec.md │ │ │ │ │ └── schema-resolution/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ ├── 2026-02-17-project-local-schemas/ │ │ │ │ ├── .openspec.yaml │ │ │ │ ├── design.md │ │ │ │ ├── proposal.md │ │ │ │ ├── specs/ │ │ │ │ │ └── schema-resolution/ │ │ │ │ │ └── spec.md │ │ │ │ └── tasks.md │ │ │ └── 2026-02-17-schema-management-cli/ │ │ │ ├── .openspec.yaml │ │ │ ├── design.md │ │ │ ├── proposal.md │ │ │ ├── specs/ │ │ │ │ ├── schema-fork-command/ │ │ │ │ │ └── spec.md │ │ │ │ ├── schema-init-command/ │ │ │ │ │ └── spec.md │ │ │ │ ├── schema-validate-command/ │ │ │ │ │ └── spec.md │ │ │ │ └── schema-which-command/ │ │ │ │ └── spec.md │ │ │ └── tasks.md │ │ ├── fix-opencode-commands-directory/ │ │ │ ├── .openspec.yaml │ │ │ ├── design.md │ │ │ ├── proposal.md │ │ │ ├── specs/ │ │ │ │ └── command-generation/ │ │ │ │ └── spec.md │ │ │ └── tasks.md │ │ ├── graceful-status-no-changes/ │ │ │ ├── .openspec.yaml │ │ │ ├── design.md │ │ │ ├── proposal.md │ │ │ ├── specs/ │ │ │ │ └── graceful-status-empty/ │ │ │ │ └── spec.md │ │ │ └── tasks.md │ │ ├── schema-alias-support/ │ │ │ ├── .openspec.yaml │ │ │ └── proposal.md │ │ ├── simplify-skill-installation/ │ │ │ ├── .openspec.yaml │ │ │ ├── design.md │ │ │ ├── proposal.md │ │ │ ├── specs/ │ │ │ │ ├── cli-init/ │ │ │ │ │ └── spec.md │ │ │ │ ├── cli-update/ │ │ │ │ │ └── spec.md │ │ │ │ ├── profiles/ │ │ │ │ │ └── spec.md │ │ │ │ └── propose-workflow/ │ │ │ │ └── spec.md │ │ │ └── tasks.md │ │ └── unify-template-generation-pipeline/ │ │ ├── .openspec.yaml │ │ ├── design.md │ │ ├── proposal.md │ │ ├── specs/ │ │ │ └── template-artifact-pipeline/ │ │ │ └── spec.md │ │ └── tasks.md │ ├── config.yaml │ ├── explorations/ │ │ ├── explore-workflow-ux.md │ │ └── workspace-architecture.md │ └── specs/ │ ├── ai-tool-paths/ │ │ └── spec.md │ ├── artifact-graph/ │ │ └── spec.md │ ├── change-creation/ │ │ └── spec.md │ ├── ci-nix-validation/ │ │ └── spec.md │ ├── cli-archive/ │ │ └── spec.md │ ├── cli-artifact-workflow/ │ │ └── spec.md │ ├── cli-change/ │ │ └── spec.md │ ├── cli-completion/ │ │ └── spec.md │ ├── cli-config/ │ │ └── spec.md │ ├── cli-feedback/ │ │ └── spec.md │ ├── cli-init/ │ │ └── spec.md │ ├── cli-list/ │ │ └── spec.md │ ├── cli-show/ │ │ └── spec.md │ ├── cli-spec/ │ │ └── spec.md │ ├── cli-update/ │ │ └── spec.md │ ├── cli-validate/ │ │ └── spec.md │ ├── cli-view/ │ │ └── spec.md │ ├── command-generation/ │ │ └── spec.md │ ├── config-loading/ │ │ └── spec.md │ ├── context-injection/ │ │ └── spec.md │ ├── docs-agent-instructions/ │ │ └── spec.md │ ├── global-config/ │ │ └── spec.md │ ├── instruction-loader/ │ │ └── spec.md │ ├── legacy-cleanup/ │ │ └── spec.md │ ├── openspec-conventions/ │ │ └── spec.md │ ├── opsx-archive-skill/ │ │ └── spec.md │ ├── opsx-onboard-skill/ │ │ └── spec.md │ ├── opsx-verify-skill/ │ │ └── spec.md │ ├── rules-injection/ │ │ └── spec.md │ ├── schema-fork-command/ │ │ └── spec.md │ ├── schema-init-command/ │ │ └── spec.md │ ├── schema-resolution/ │ │ └── spec.md │ ├── schema-validate-command/ │ │ └── spec.md │ ├── schema-which-command/ │ │ └── spec.md │ ├── specs-sync-skill/ │ │ └── spec.md │ └── telemetry/ │ └── spec.md ├── openspec-parallel-merge-plan.md ├── package.json ├── schemas/ │ └── spec-driven/ │ ├── schema.yaml │ └── templates/ │ ├── design.md │ ├── proposal.md │ ├── spec.md │ └── tasks.md ├── scripts/ │ ├── README.md │ ├── pack-version-check.mjs │ ├── postinstall.js │ ├── test-postinstall.sh │ └── update-flake.sh ├── src/ │ ├── cli/ │ │ └── index.ts │ ├── commands/ │ │ ├── change.ts │ │ ├── completion.ts │ │ ├── config.ts │ │ ├── feedback.ts │ │ ├── schema.ts │ │ ├── show.ts │ │ ├── spec.ts │ │ ├── validate.ts │ │ └── workflow/ │ │ ├── index.ts │ │ ├── instructions.ts │ │ ├── new-change.ts │ │ ├── schemas.ts │ │ ├── shared.ts │ │ ├── status.ts │ │ └── templates.ts │ ├── core/ │ │ ├── archive.ts │ │ ├── artifact-graph/ │ │ │ ├── graph.ts │ │ │ ├── index.ts │ │ │ ├── instruction-loader.ts │ │ │ ├── resolver.ts │ │ │ ├── schema.ts │ │ │ ├── state.ts │ │ │ └── types.ts │ │ ├── available-tools.ts │ │ ├── command-generation/ │ │ │ ├── adapters/ │ │ │ │ ├── amazon-q.ts │ │ │ │ ├── antigravity.ts │ │ │ │ ├── auggie.ts │ │ │ │ ├── claude.ts │ │ │ │ ├── cline.ts │ │ │ │ ├── codebuddy.ts │ │ │ │ ├── codex.ts │ │ │ │ ├── continue.ts │ │ │ │ ├── costrict.ts │ │ │ │ ├── crush.ts │ │ │ │ ├── cursor.ts │ │ │ │ ├── factory.ts │ │ │ │ ├── gemini.ts │ │ │ │ ├── github-copilot.ts │ │ │ │ ├── iflow.ts │ │ │ │ ├── index.ts │ │ │ │ ├── kilocode.ts │ │ │ │ ├── kiro.ts │ │ │ │ ├── opencode.ts │ │ │ │ ├── pi.ts │ │ │ │ ├── qoder.ts │ │ │ │ ├── qwen.ts │ │ │ │ ├── roocode.ts │ │ │ │ └── windsurf.ts │ │ │ ├── generator.ts │ │ │ ├── index.ts │ │ │ ├── registry.ts │ │ │ └── types.ts │ │ ├── completions/ │ │ │ ├── command-registry.ts │ │ │ ├── completion-provider.ts │ │ │ ├── factory.ts │ │ │ ├── generators/ │ │ │ │ ├── bash-generator.ts │ │ │ │ ├── fish-generator.ts │ │ │ │ ├── powershell-generator.ts │ │ │ │ └── zsh-generator.ts │ │ │ ├── installers/ │ │ │ │ ├── bash-installer.ts │ │ │ │ ├── fish-installer.ts │ │ │ │ ├── powershell-installer.ts │ │ │ │ └── zsh-installer.ts │ │ │ ├── templates/ │ │ │ │ ├── bash-templates.ts │ │ │ │ ├── fish-templates.ts │ │ │ │ ├── powershell-templates.ts │ │ │ │ └── zsh-templates.ts │ │ │ └── types.ts │ │ ├── config-prompts.ts │ │ ├── config-schema.ts │ │ ├── config.ts │ │ ├── converters/ │ │ │ └── json-converter.ts │ │ ├── global-config.ts │ │ ├── index.ts │ │ ├── init.ts │ │ ├── legacy-cleanup.ts │ │ ├── list.ts │ │ ├── migration.ts │ │ ├── parsers/ │ │ │ ├── change-parser.ts │ │ │ ├── markdown-parser.ts │ │ │ └── requirement-blocks.ts │ │ ├── profile-sync-drift.ts │ │ ├── profiles.ts │ │ ├── project-config.ts │ │ ├── schemas/ │ │ │ ├── base.schema.ts │ │ │ ├── change.schema.ts │ │ │ ├── index.ts │ │ │ └── spec.schema.ts │ │ ├── shared/ │ │ │ ├── index.ts │ │ │ ├── skill-generation.ts │ │ │ └── tool-detection.ts │ │ ├── specs-apply.ts │ │ ├── styles/ │ │ │ └── palette.ts │ │ ├── templates/ │ │ │ ├── index.ts │ │ │ ├── skill-templates.ts │ │ │ ├── types.ts │ │ │ └── workflows/ │ │ │ ├── apply-change.ts │ │ │ ├── archive-change.ts │ │ │ ├── bulk-archive-change.ts │ │ │ ├── continue-change.ts │ │ │ ├── explore.ts │ │ │ ├── feedback.ts │ │ │ ├── ff-change.ts │ │ │ ├── new-change.ts │ │ │ ├── onboard.ts │ │ │ ├── propose.ts │ │ │ ├── sync-specs.ts │ │ │ └── verify-change.ts │ │ ├── update.ts │ │ ├── validation/ │ │ │ ├── constants.ts │ │ │ ├── types.ts │ │ │ └── validator.ts │ │ └── view.ts │ ├── index.ts │ ├── prompts/ │ │ └── searchable-multi-select.ts │ ├── telemetry/ │ │ ├── config.ts │ │ └── index.ts │ ├── ui/ │ │ ├── ascii-patterns.ts │ │ └── welcome-screen.ts │ └── utils/ │ ├── change-metadata.ts │ ├── change-utils.ts │ ├── command-references.ts │ ├── file-system.ts │ ├── index.ts │ ├── interactive.ts │ ├── item-discovery.ts │ ├── match.ts │ ├── shell-detection.ts │ └── task-progress.ts ├── test/ │ ├── cli-e2e/ │ │ └── basic.test.ts │ ├── commands/ │ │ ├── artifact-workflow.test.ts │ │ ├── change.interactive-show.test.ts │ │ ├── change.interactive-validate.test.ts │ │ ├── completion.test.ts │ │ ├── config-profile.test.ts │ │ ├── config.test.ts │ │ ├── feedback.test.ts │ │ ├── schema.test.ts │ │ ├── show.test.ts │ │ ├── spec.interactive-show.test.ts │ │ ├── spec.interactive-validate.test.ts │ │ ├── spec.test.ts │ │ ├── validate.enriched-output.test.ts │ │ └── validate.test.ts │ ├── core/ │ │ ├── archive.test.ts │ │ ├── artifact-graph/ │ │ │ ├── graph.test.ts │ │ │ ├── instruction-loader.test.ts │ │ │ ├── resolver.test.ts │ │ │ ├── schema.test.ts │ │ │ ├── state.test.ts │ │ │ └── workflow.integration.test.ts │ │ ├── available-tools.test.ts │ │ ├── command-generation/ │ │ │ ├── adapters.test.ts │ │ │ ├── generator.test.ts │ │ │ ├── registry.test.ts │ │ │ └── types.test.ts │ │ ├── commands/ │ │ │ ├── change-command.list.test.ts │ │ │ └── change-command.show-validate.test.ts │ │ ├── completions/ │ │ │ ├── completion-provider.test.ts │ │ │ ├── generators/ │ │ │ │ ├── bash-generator.test.ts │ │ │ │ ├── fish-generator.test.ts │ │ │ │ ├── powershell-generator.test.ts │ │ │ │ └── zsh-generator.test.ts │ │ │ └── installers/ │ │ │ ├── bash-installer.test.ts │ │ │ ├── fish-installer.test.ts │ │ │ ├── powershell-installer.test.ts │ │ │ └── zsh-installer.test.ts │ │ ├── config-schema.test.ts │ │ ├── converters/ │ │ │ └── json-converter.test.ts │ │ ├── global-config.test.ts │ │ ├── init.test.ts │ │ ├── legacy-cleanup.test.ts │ │ ├── list.test.ts │ │ ├── migration.test.ts │ │ ├── parsers/ │ │ │ ├── change-parser.test.ts │ │ │ └── markdown-parser.test.ts │ │ ├── profile-sync-drift.test.ts │ │ ├── profiles.test.ts │ │ ├── project-config.test.ts │ │ ├── shared/ │ │ │ ├── skill-generation.test.ts │ │ │ └── tool-detection.test.ts │ │ ├── templates/ │ │ │ └── skill-templates-parity.test.ts │ │ ├── update.test.ts │ │ ├── validation.enriched-messages.test.ts │ │ ├── validation.test.ts │ │ └── view.test.ts │ ├── fixtures/ │ │ └── tmp-init/ │ │ └── openspec/ │ │ ├── changes/ │ │ │ └── c1/ │ │ │ ├── proposal.md │ │ │ └── specs/ │ │ │ └── alpha/ │ │ │ └── spec.md │ │ └── specs/ │ │ └── alpha/ │ │ └── spec.md │ ├── helpers/ │ │ └── run-cli.ts │ ├── prompts/ │ │ └── searchable-multi-select.test.ts │ ├── specs/ │ │ └── source-specs-normalization.test.ts │ ├── telemetry/ │ │ ├── config.test.ts │ │ └── index.test.ts │ └── utils/ │ ├── change-metadata.test.ts │ ├── change-utils.test.ts │ ├── command-references.test.ts │ ├── file-system.test.ts │ ├── interactive.test.ts │ ├── marker-updates.test.ts │ └── shell-detection.test.ts ├── tsconfig.json ├── vitest.config.ts └── vitest.setup.ts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .actrc ================================================ -P ubuntu-latest=catthehacker/ubuntu:act-latest ================================================ FILE: .changeset/README.md ================================================ # Changesets This directory is managed by [Changesets](https://github.com/changesets/changesets). ## Quick Start ```bash pnpm changeset ``` Follow the prompts to select version bump type and describe your changes. ## Workflow 1. **Add a changeset** — Run `pnpm changeset` locally before or after your PR 2. **Version PR** — CI opens/updates a "Version Packages" PR when changesets merge to main 3. **Release** — Merging the Version PR triggers npm publish and GitHub Release > **Note:** Contributors only need to run `pnpm changeset`. Versioning (`changeset version`) and publishing happen automatically in CI. ## Template Use this structure for your changeset content: ```markdown --- "@fission-ai/openspec": patch --- ### New Features - **Feature name** — What users can now do ### Bug Fixes - Fixed issue where X happened when Y ### Breaking Changes - `oldMethod()` has been removed, use `newMethod()` instead ### Deprecations - `legacyOption` is deprecated and will be removed in v2.0 ### Other - Internal refactoring of X for better performance ``` Include only the sections relevant to your change. ## Version Bump Guide | Type | When to use | Example | |------|-------------|---------| | `patch` | Bug fixes, small improvements | Fixed crash when config missing | | `minor` | New features, non-breaking additions | Added `--verbose` flag | | `major` | Breaking changes, removed features | Renamed `init` to `setup` | ## When to Create a Changeset **Create one for:** - New features or commands - Bug fixes that affect users - Breaking changes or deprecations - Performance improvements users would notice **Skip for:** - Documentation-only changes - Test additions/fixes - Internal refactoring with no user impact - CI/tooling changes ## Writing Good Descriptions **Do:** Write for users, not developers ```markdown - **Shell completions** — Tab completion now available for Bash, Fish, and PowerShell ``` **Don't:** Write implementation details ```markdown - Added ShellCompletionGenerator class with Bash/Fish/PowerShell subclasses ``` **Do:** Explain the impact ```markdown - Fixed config loading to respect `XDG_CONFIG_HOME` on Linux ``` **Don't:** Just reference the fix ```markdown - Fixed #123 ``` ================================================ FILE: .changeset/config.json ================================================ { "$schema": "https://unpkg.com/@changesets/config/schema.json", "changelog": [ "@changesets/changelog-github", { "repo": "Fission-AI/OpenSpec" } ], "commit": false, "fixed": [], "linked": [], "access": "public", "baseBranch": "main", "updateInternalDependencies": "patch", "ignore": [] } ================================================ FILE: .changeset/fix-opencode-commands-directory.md ================================================ --- "@fission-ai/openspec": patch --- fix: OpenCode adapter now uses `.opencode/commands/` (plural) to match OpenCode's official directory convention. Fixes #748. ================================================ FILE: .changeset/graceful-status-no-changes.md ================================================ --- "@fission-ai/openspec": patch --- fix: `openspec status` now exits gracefully when no changes exist instead of throwing a fatal error. Fixes #714. ================================================ FILE: .coderabbit.yaml ================================================ # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json # Minimal configuration for getting started language: "en-US" reviews: profile: "chill" high_level_summary: true auto_review: enabled: true drafts: false base_branches: - ".*" ================================================ FILE: .devcontainer/README.md ================================================ # Dev Container Setup This directory contains the VS Code dev container configuration for OpenSpec development. ## What's Included - **Node.js 20 LTS** (>=20.19.0) - TypeScript/JavaScript runtime - **pnpm** - Fast, disk space efficient package manager - **Git + GitHub CLI** - Version control tools - **VS Code Extensions**: - ESLint & Prettier for code quality - Vitest Explorer for running tests - GitLens for enhanced git integration - Error Lens for inline error highlighting - Code Spell Checker - Path IntelliSense ## How to Use ### First Time Setup 1. **Install Prerequisites** (on your local machine): - [VS Code](https://code.visualstudio.com/) - [Docker Desktop](https://www.docker.com/products/docker-desktop) - [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) 2. **Open in Container**: - Open this project in VS Code - You'll see a notification: "Folder contains a Dev Container configuration file" - Click "Reopen in Container" OR - Open Command Palette (`Cmd/Ctrl+Shift+P`) - Type "Dev Containers: Reopen in Container" - Press Enter 3. **Wait for Setup**: - The container will build (first time takes a few minutes) - `pnpm install` runs automatically via `postCreateCommand` - All extensions install automatically ### Daily Development Once set up, the container preserves your development environment: ```bash # Run development build pnpm run dev # Run CLI in development pnpm run dev:cli # Run tests pnpm test # Run tests in watch mode pnpm test:watch # Build the project pnpm run build ``` ### SSH Keys Your SSH keys are mounted read-only from `~/.ssh`, so git operations work seamlessly with GitHub/GitLab. ### Rebuilding the Container If you modify `.devcontainer/devcontainer.json`: - Command Palette → "Dev Containers: Rebuild Container" ## Benefits - No need to install Node.js or pnpm on your local machine - Consistent development environment across team members - Isolated from other Node.js projects on your machine - All dependencies and tools containerized - Easy onboarding for new developers ## Troubleshooting **Container won't build:** - Ensure Docker Desktop is running - Check Docker has enough memory allocated (recommend 4GB+) **Extensions not appearing:** - Rebuild the container: "Dev Containers: Rebuild Container" **Permission issues:** - The container runs as the `node` user (non-root) - Files created in the container are owned by this user ================================================ FILE: .devcontainer/devcontainer.json ================================================ { "name": "OpenSpec Development", "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bookworm", // Additional tools and features "features": { "ghcr.io/devcontainers/features/git:1": { "version": "latest", "ppa": true }, "ghcr.io/devcontainers/features/github-cli:1": { "version": "latest" } }, // Configure tool-specific properties "customizations": { "vscode": { // Set default container specific settings "settings": { "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { "source.fixAll": "explicit" }, "files.eol": "\n", "terminal.integrated.defaultProfile.linux": "bash" }, // Add extensions you want installed when the container is created "extensions": [ // TypeScript/JavaScript essentials "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", // Testing "vitest.explorer", // Git "eamodio.gitlens", // Utilities "streetsidesoftware.code-spell-checker", "usernamehw.errorlens", "christian-kohler.path-intellisense" ] } }, // Use 'forwardPorts' to make a list of ports inside the container available locally // "forwardPorts": [], // Use 'postCreateCommand' to run commands after the container is created "postCreateCommand": "corepack enable && corepack prepare pnpm@latest --activate && pnpm install", // Configure mounts to preserve SSH keys for git operations "mounts": [ "source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/node/.ssh,readonly,type=bind,consistency=cached" ], // Set the default user to 'node' (non-root user) "remoteUser": "node", // Ensure git is properly configured "initializeCommand": "echo 'Initializing dev container...'" } ================================================ FILE: .github/CODEOWNERS ================================================ # Default code ownership * @TabishB ================================================ FILE: .github/workflows/README.md ================================================ # Github Workflows ## Testing CI Locally Test GitHub Actions workflows locally using [act](https://nektosact.com/): ```bash # Test all PR checks act pull_request # Test specific job act pull_request -j nix-flake-validate # Dry run to see what would execute act pull_request --dryrun ``` The `.actrc` file configures act to use the appropriate Docker image. ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: pull_request: branches: [main] push: branches: [main] workflow_dispatch: permissions: contents: read concurrency: group: ci-${{ github.ref }} cancel-in-progress: true jobs: # Detect which files changed to enable path-based filtering changes: name: Detect changes runs-on: ubuntu-latest outputs: nix: ${{ steps.filter.outputs.nix }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Check for Nix-related changes uses: dorny/paths-filter@v3 id: filter with: filters: | nix: - 'flake.nix' - 'flake.lock' - 'package.json' - 'pnpm-lock.yaml' - 'scripts/update-flake.sh' - '.github/workflows/ci.yml' test_pr: name: Test runs-on: ubuntu-latest timeout-minutes: 10 if: github.event_name == 'pull_request' steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'pnpm' - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build project run: pnpm run build - name: Run tests run: pnpm test - name: Upload test coverage uses: actions/upload-artifact@v4 with: name: coverage-report-pr path: coverage/ retention-days: 7 test_matrix: name: Test (${{ matrix.label }}) runs-on: ${{ matrix.os }} timeout-minutes: 15 if: github.event_name != 'pull_request' strategy: fail-fast: false matrix: include: - os: ubuntu-latest shell: bash label: linux-bash - os: macos-latest shell: bash label: macos-bash - os: windows-latest shell: pwsh label: windows-pwsh defaults: run: shell: ${{ matrix.shell }} steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'pnpm' - name: Print environment diagnostics run: | node -p "JSON.stringify({ platform: process.platform, arch: process.arch, shell: process.env.SHELL || process.env.ComSpec || '' })" - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build project run: pnpm run build - name: Run tests run: pnpm test - name: Upload test coverage if: matrix.os == 'ubuntu-latest' uses: actions/upload-artifact@v4 with: name: coverage-report-main path: coverage/ retention-days: 7 lint: name: Lint & Type Check runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'pnpm' - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build project run: pnpm run build - name: Type check run: pnpm exec tsc --noEmit - name: Lint run: pnpm lint - name: Check for build artifacts run: | if [ ! -d "dist" ]; then echo "Error: dist directory not found after build" exit 1 fi if [ ! -f "dist/cli/index.js" ]; then echo "Error: CLI entry point not found" exit 1 fi nix-flake-validate: name: Nix Flake Validation runs-on: ubuntu-latest timeout-minutes: 10 needs: changes if: needs.changes.outputs.nix == 'true' steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Nix uses: DeterminateSystems/nix-installer-action@v21 - name: Setup Nix cache uses: DeterminateSystems/magic-nix-cache-action@v13 - name: Build with Nix run: nix build - name: Verify build output run: | if [ ! -e "result" ]; then echo "Error: Nix build output 'result' symlink not found" exit 1 fi if [ ! -f "result/bin/openspec" ]; then echo "Error: openspec binary not found in build output" exit 1 fi echo "✅ Build output verified" - name: Test binary execution run: | VERSION=$(nix run . -- --version) echo "OpenSpec version: $VERSION" if [ -z "$VERSION" ]; then echo "Error: Version command returned empty output" exit 1 fi echo "✅ Binary execution successful" - name: Validate update script run: | echo "Testing update-flake.sh script..." bash scripts/update-flake.sh echo "✅ Update script executed successfully" - name: Check flake.nix modifications run: | if git diff --quiet flake.nix; then echo "ℹ️ flake.nix unchanged (hash already up-to-date)" else echo "✅ flake.nix was updated by script" git diff flake.nix fi - name: Restore flake.nix if: always() run: git checkout -- flake.nix || true validate-changesets: name: Validate Changesets runs-on: ubuntu-latest if: github.event_name == 'pull_request' steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'pnpm' - name: Install dependencies run: pnpm install --frozen-lockfile - name: Validate changesets run: | if command -v changeset &> /dev/null; then pnpm exec changeset status --since=origin/main else echo "Changesets not configured, skipping validation" fi required-checks-pr: name: All checks passed runs-on: ubuntu-latest needs: [test_pr, lint, nix-flake-validate] if: always() && github.event_name == 'pull_request' steps: - name: Verify all checks passed run: | if [[ "${{ needs.test_pr.result }}" != "success" ]]; then echo "Test job failed" exit 1 fi if [[ "${{ needs.lint.result }}" != "success" ]]; then echo "Lint job failed" exit 1 fi # Nix validation may be skipped if no Nix-related files changed if [[ "${{ needs.nix-flake-validate.result }}" != "success" && "${{ needs.nix-flake-validate.result }}" != "skipped" ]]; then echo "Nix flake validation job failed" exit 1 fi if [[ "${{ needs.nix-flake-validate.result }}" == "skipped" ]]; then echo "Nix flake validation skipped (no Nix-related changes)" fi echo "All required checks passed!" required-checks-main: name: All checks passed runs-on: ubuntu-latest needs: [test_matrix, lint, nix-flake-validate] if: always() && github.event_name != 'pull_request' steps: - name: Verify all checks passed run: | if [[ "${{ needs.test_matrix.result }}" != "success" ]]; then echo "Matrix test job failed" exit 1 fi if [[ "${{ needs.lint.result }}" != "success" ]]; then echo "Lint job failed" exit 1 fi # Nix validation may be skipped if no Nix-related files changed if [[ "${{ needs.nix-flake-validate.result }}" != "success" && "${{ needs.nix-flake-validate.result }}" != "skipped" ]]; then echo "Nix flake validation job failed" exit 1 fi if [[ "${{ needs.nix-flake-validate.result }}" == "skipped" ]]; then echo "Nix flake validation skipped (no Nix-related changes)" fi echo "All required checks passed!" ================================================ FILE: .github/workflows/release-prepare.yml ================================================ name: Release (prepare) on: push: branches: [main] permissions: contents: write pull-requests: write id-token: write # Required for npm OIDC trusted publishing concurrency: group: release-${{ github.ref }} cancel-in-progress: false jobs: prepare: if: github.repository == 'Fission-AI/OpenSpec' runs-on: ubuntu-latest steps: # Generate GitHub App token first - used for checkout and changesets # This allows git operations to trigger CI workflows on the version PR # (GITHUB_TOKEN cannot trigger workflows by design) - name: Generate GitHub App Token id: app-token uses: actions/create-github-app-token@v2 with: app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} - uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ steps.app-token.outputs.token }} - uses: pnpm/action-setup@v4 with: version: 9 - uses: actions/setup-node@v4 with: node-version: '24' # Node 24 includes npm 11.5.1+ required for OIDC cache: 'pnpm' registry-url: 'https://registry.npmjs.org' - run: pnpm install --frozen-lockfile # Opens/updates the Version Packages PR; publishes when the Version PR merges - name: Create/Update Version PR id: changesets uses: changesets/action@v1 with: title: 'chore(release): version packages' createGithubReleases: true # Use CI-specific release script: relies on version PR having been merged # so package.json already contains the bumped version. publish: pnpm run release:ci env: GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} # npm authentication handled via OIDC trusted publishing (no token needed) ================================================ FILE: .gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage *.lcov # nyc test coverage .nyc_output # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Snowpack dependency directory (https://snowpack.dev/) web_modules/ # TypeScript cache *.tsbuildinfo # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional stylelint cache .stylelintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variable files .env .env.* !.env.example # parcel-bundler cache (https://parceljs.org/) .cache .parcel-cache # Next.js build output .next out # Nuxt.js build / generate output .nuxt # Build output dist/ # Gatsby files .cache/ # Comment in the public line in if your project uses Gatsby and not Next.js # https://nextjs.org/blog/next-9-1#public-directory-support # public # vuepress build output .vuepress/dist # vuepress v2.x temp and cache directory .temp .cache # Sveltekit cache directory .svelte-kit/ # vitepress build output **/.vitepress/dist # vitepress cache directory **/.vitepress/cache # Docusaurus cache and generated files .docusaurus # Serverless directories .serverless/ # FuseBox cache .fusebox/ # DynamoDB Local files .dynamodb/ # Firebase cache directory .firebase/ # TernJS port file .tern-port # Stores VSCode versions used for testing VSCode extensions .vscode-test # yarn v3 .pnp.* .yarn/* !.yarn/patches !.yarn/plugins !.yarn/releases !.yarn/sdks !.yarn/versions # Vite logs files vite.config.js.timestamp-* vite.config.ts.timestamp-* # Claude .claude/ CLAUDE.md .DS_Store # Pnpm .pnpm-store/ result # OpenCode .opencode/ opencode.json # Codex .codex/ ================================================ FILE: AGENTS.md ================================================ ================================================ FILE: CHANGELOG.md ================================================ # @fission-ai/openspec ## 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 - [#627](https://github.com/Fission-AI/OpenSpec/pull/627) [`afb73cf`](https://github.com/Fission-AI/OpenSpec/commit/afb73cf9ec59c6f8b26d0c538c0218c203ba3c56) Thanks [@TabishB](https://github.com/TabishB)! - ### Bug Fixes - **OpenCode command references** — Command references in generated files now use the correct `/opsx-` hyphen format instead of `/opsx:` colon format, ensuring commands work properly in OpenCode ## 1.1.0 ### Minor Changes - [#625](https://github.com/Fission-AI/OpenSpec/pull/625) [`53081fb`](https://github.com/Fission-AI/OpenSpec/commit/53081fb2a26ec66d2950ae0474b9a56cbc5b5a76) Thanks [@TabishB](https://github.com/TabishB)! - ### Bug Fixes - **Codex global path support** — Codex adapter now resolves global paths correctly, fixing workflow file generation when run outside the project directory (#622) - **Archive operations on cross-device or restricted paths** — Archive now falls back to copy+remove when rename fails with EPERM or EXDEV errors, fixing failures on networked/external drives (#605) - **Slash command hints in workflow messages** — Workflow completion messages now display helpful slash command hints for next steps (#603) - **Windsurf workflow file path** — Updated Windsurf adapter to use the correct `workflows` directory instead of the legacy `commands` path (#610) ### Patch Changes - [#550](https://github.com/Fission-AI/OpenSpec/pull/550) [`86d2e04`](https://github.com/Fission-AI/OpenSpec/commit/86d2e04cae76a999dbd1b4571f52fa720036be0c) Thanks [@jerome-benoit](https://github.com/jerome-benoit)! - ### Improvements - **Nix flake maintenance** — Version now read dynamically from package.json, reducing manual sync issues - **Nix build optimization** — Source filtering excludes node_modules and artifacts, improving build times - **update-flake.sh script** — Detects when hash is already correct, skipping unnecessary rebuilds ### Other - Updated Nix CI actions to latest versions (nix-installer v21, magic-nix-cache v13) ## 1.0.2 ### Patch Changes - [#596](https://github.com/Fission-AI/OpenSpec/pull/596) [`e91568d`](https://github.com/Fission-AI/OpenSpec/commit/e91568deb948073f3e9d9bb2d2ab5bf8080d6cf4) Thanks [@TabishB](https://github.com/TabishB)! - ### Bug Fixes - Clarified spec naming convention — Specs should be named after capabilities (`specs//spec.md`), not changes - Fixed task checkbox format guidance — Tasks now clearly require `- [ ]` checkbox format for apply phase tracking ## 1.0.1 ### Patch Changes - [#587](https://github.com/Fission-AI/OpenSpec/pull/587) [`943e0d4`](https://github.com/Fission-AI/OpenSpec/commit/943e0d41026d034de66b9442d1276c01b293eb2b) Thanks [@TabishB](https://github.com/TabishB)! - ### Bug Fixes - Fixed incorrect archive path in onboarding documentation — the template now shows the correct path `openspec/changes/archive/YYYY-MM-DD-/` instead of the incorrect `openspec/archive/YYYY-MM-DD--/` ## 1.0.0 ### Major Changes - [#578](https://github.com/Fission-AI/OpenSpec/pull/578) [`0cc9d90`](https://github.com/Fission-AI/OpenSpec/commit/0cc9d9025af367faa1688a7b2606a2549053cd3f) Thanks [@TabishB](https://github.com/TabishB)! - ## OpenSpec 1.0 — The OPSX Release The workflow has been rebuilt from the ground up. OPSX replaces the old phase-locked `/openspec:*` commands with an action-based system where AI understands what artifacts exist, what's ready to create, and what each action unlocks. ### Breaking Changes - **Old commands removed** — `/openspec:proposal`, `/openspec:apply`, and `/openspec:archive` no longer exist - **Config files removed** — Tool-specific instruction files (`CLAUDE.md`, `.cursorrules`, `AGENTS.md`, `project.md`) are no longer generated - **Migration** — Run `openspec init` to upgrade. Legacy artifacts are detected and cleaned up with confirmation. ### From Static Prompts to Dynamic Instructions **Before:** AI received the same static instructions every time, regardless of project state. **Now:** Instructions are dynamically assembled from three layers: 1. **Context** — Project background from `config.yaml` (tech stack, conventions) 2. **Rules** — Artifact-specific constraints (e.g., "propose spike tasks for unknowns") 3. **Template** — The actual structure for the output file AI queries the CLI for real-time state: which artifacts exist, what's ready to create, what dependencies are satisfied, and what each action unlocks. ### From Phase-Locked to Action-Based **Before:** Linear workflow — proposal → apply → archive. Couldn't easily go back or iterate. **Now:** Flexible actions on a change. Edit any artifact anytime. The artifact graph tracks state automatically. | Command | What it does | | -------------------- | ---------------------------------------------------- | | `/opsx:explore` | Think through ideas before committing to a change | | `/opsx:new` | Start a new change | | `/opsx:continue` | Create one artifact at a time (step-through) | | `/opsx:ff` | Create all planning artifacts at once (fast-forward) | | `/opsx:apply` | Implement tasks | | `/opsx:verify` | Validate implementation matches artifacts | | `/opsx:sync` | Sync delta specs to main specs | | `/opsx:archive` | Archive completed change | | `/opsx:bulk-archive` | Archive multiple changes with conflict detection | | `/opsx:onboard` | Guided 15-minute walkthrough of complete workflow | ### From Text Merging to Semantic Spec Syncing **Before:** Spec updates required manual merging or wholesale file replacement. **Now:** Delta specs use semantic markers that AI understands: - `## ADDED Requirements` — New requirements to add - `## MODIFIED Requirements` — Partial updates (add scenario without copying existing ones) - `## REMOVED Requirements` — Delete with reason and migration notes - `## RENAMED Requirements` — Rename preserving content Archive parses these at the requirement level, not brittle header matching. ### From Scattered Files to Agent Skills **Before:** 8+ config files at project root + slash commands scattered across 21 tool-specific locations with different formats. **Now:** Single `.claude/skills/` directory with YAML-fronted markdown files. Auto-detected by Claude Code, Cursor, Windsurf. Cross-editor compatible. ### New Features - **Onboarding skill** — `/opsx:onboard` walks new users through their first complete change with codebase-aware task suggestions and step-by-step narration (11 phases, ~15 minutes) - **21 AI tools supported** — Claude Code, Cursor, Windsurf, Continue, Gemini CLI, GitHub Copilot, Amazon Q, Cline, RooCode, Kilo Code, Auggie, CodeBuddy, Qoder, Qwen, CoStrict, Crush, Factory, OpenCode, Antigravity, iFlow, and Codex - **Interactive setup** — `openspec init` shows animated welcome screen and searchable multi-select for choosing tools. Pre-selects already-configured tools for easy refresh. - **Customizable schemas** — Define custom artifact workflows in `openspec/schemas/` without touching package code. Teams can share workflows via version control. ### Bug Fixes - Fixed Claude Code YAML parsing failure when command names contained colons - Fixed task file parsing to handle trailing whitespace on checkbox lines - Fixed JSON instruction output to separate context/rules from template — AI was copying constraint blocks into artifact files ### Documentation - New getting-started guide, CLI reference, concepts documentation - Removed misleading "edit mid-flight and continue" claims that weren't implemented - Added migration guide for upgrading from pre-OPSX versions ## 0.23.0 ### Minor Changes - [#540](https://github.com/Fission-AI/OpenSpec/pull/540) [`c4cfdc7`](https://github.com/Fission-AI/OpenSpec/commit/c4cfdc7c499daef30d8a218f5f59b8d9e5adb754) Thanks [@TabishB](https://github.com/TabishB)! - ### New Features - **Bulk archive skill** — Archive multiple completed changes in a single operation with `/opsx:bulk-archive`. Includes batch validation, spec conflict detection, and consolidated confirmation ### Other - **Simplified setup** — Config creation now uses sensible defaults with helpful comments instead of interactive prompts ## 0.22.0 ### Minor Changes - [#530](https://github.com/Fission-AI/OpenSpec/pull/530) [`33466b1`](https://github.com/Fission-AI/OpenSpec/commit/33466b1e2a6798bdd6d0e19149173585b0612e6f) Thanks [@TabishB](https://github.com/TabishB)! - Add project-level configuration, project-local schemas, and schema management commands **New Features** - **Project-level configuration** — Configure OpenSpec behavior per-project via `openspec/config.yaml`, including custom rules injection, context files, and schema resolution settings - **Project-local schemas** — Define custom artifact schemas within your project's `openspec/schemas/` directory for project-specific workflows - **Schema management commands** — New `openspec schema` commands (`list`, `show`, `export`, `validate`) for inspecting and managing artifact schemas (experimental) **Bug Fixes** - Fixed config loading to handle null `rules` field in project configuration ## 0.21.0 ### Minor Changes - [#516](https://github.com/Fission-AI/OpenSpec/pull/516) [`b5a8847`](https://github.com/Fission-AI/OpenSpec/commit/b5a884748be6156a7bb140b4941cfec4f20a9fc8) Thanks [@TabishB](https://github.com/TabishB)! - Add feedback command and Nix flake support **New Features** - **Feedback command** — Submit feedback directly from the CLI with `openspec feedback`, which creates GitHub Issues with automatic metadata inclusion and graceful fallback for manual submission - **Nix flake support** — Install and develop openspec using Nix with the new `flake.nix`, including automated flake maintenance and CI validation **Bug Fixes** - **Explore mode guardrails** — Explore mode now explicitly prevents implementation, keeping the focus on thinking and discovery while still allowing artifact creation **Other** - Improved change inference in `opsx apply` — automatically detects the target change from conversation context or prompts when ambiguous - Streamlined archive sync assessment with clearer delta spec location guidance ## 0.20.0 ### Minor Changes - [#502](https://github.com/Fission-AI/OpenSpec/pull/502) [`9db74aa`](https://github.com/Fission-AI/OpenSpec/commit/9db74aa5ac6547efadaed795217cfa17444f2004) Thanks [@TabishB](https://github.com/TabishB)! - Add `/opsx:verify` command and fix vitest process storms **New Features** - **`/opsx:verify` command** — Validate that change implementations match their specifications **Bug Fixes** - Fixed vitest process storms by capping worker parallelism - Fixed agent workflows to use non-interactive mode for validation commands - Fixed PowerShell completions generator to remove trailing commas ## 0.19.0 ### Minor Changes - eb152eb: Add Continue IDE support, shell completions, and `/opsx:explore` command **New Features** - **Continue IDE support** – OpenSpec now generates slash commands for [Continue](https://continue.dev/), expanding editor integration options alongside Cursor, Windsurf, Claude Code, and others - **Shell completions for Bash, Fish, and PowerShell** – Run `openspec completion install` to set up tab completion in your preferred shell - **`/opsx:explore` command** – A new thinking partner mode for exploring ideas and investigating problems before committing to changes - **Codebuddy slash command improvements** – Updated frontmatter format for better compatibility **Bug Fixes** - Shell completions now correctly offer parent-level flags (like `--help`) when a command has subcommands - Fixed Windows compatibility issues in tests **Other** - Added optional anonymous usage statistics to help understand how OpenSpec is used. This is **opt-out** by default – set `OPENSPEC_TELEMETRY=0` or `DO_NOT_TRACK=1` to disable. Only command names and version are collected; no arguments, file paths, or content. Automatically disabled in CI environments. ## 0.18.0 ### Minor Changes - 8dfd824: Add OPSX experimental workflow commands and enhanced artifact system **New Commands:** - `/opsx:ff` - Fast-forward through artifact creation, generating all needed artifacts in one go - `/opsx:sync` - Sync delta specs from a change to main specs - `/opsx:archive` - Archive completed changes with smart sync check **Artifact Workflow Enhancements:** - Schema-aware apply instructions with inline guidance and XML output - Agent schema selection for experimental artifact workflow - Per-change schema metadata via `.openspec.yaml` files - Agent Skills for experimental artifact workflow - Instruction loader for template loading and change context - Restructured schemas as directories with templates **Improvements:** - Enhanced list command with last modified timestamps and sorting - Change creation utilities for better workflow support **Fixes:** - Normalize paths for cross-platform glob compatibility - Allow REMOVED requirements when creating new spec files ## 0.17.2 ### Patch Changes - 455c65f: Fix `--no-interactive` flag in validate command to properly disable spinner, preventing hangs in pre-commit hooks and CI environments ## 0.17.1 ### Patch Changes - a2757e7: Fix pre-commit hook hang issue in config command by using dynamic import for @inquirer/prompts The config command was causing pre-commit hooks to hang indefinitely due to stdin event listeners being registered at module load time. This fix converts the static import to a dynamic import that only loads inquirer when the `config reset` command is actually used interactively. Also adds ESLint with a rule to prevent static @inquirer imports, avoiding future regressions. ## 0.17.0 ### Minor Changes - 2e71835: Add `openspec config` command and Oh-my-zsh completions **New Features** - Add `openspec config` command for managing global configuration settings - Implement global config directory with XDG Base Directory specification support - Add Oh-my-zsh shell completions support for enhanced CLI experience **Bug Fixes** - Fix hang in pre-commit hooks by using dynamic imports - Respect XDG_CONFIG_HOME environment variable on all platforms - Resolve Windows compatibility issues in zsh-installer tests - Align cli-completion spec with implementation - Remove hardcoded agent field from slash commands **Documentation** - Alphabetize AI tools list in README and make it collapsible ## 0.16.0 ### Minor Changes - c08fbc1: Add new AI tool integrations and enhancements: - **feat(iflow-cli)**: Add iFlow-cli integration with slash command support and documentation - **feat(init)**: Add IDE restart instruction after init to inform users about slash command availability **feat(antigravity)**: Add Antigravity slash command support - **fix**: Generate TOML commands for Qwen Code (fixes #293) - Clarify scaffold proposal documentation and enhance proposal guidelines - Update proposal guidelines to emphasize design-first approach before implementation ## Unreleased ### Minor Changes - Add Continue slash command support so `openspec init` can generate `.continue/prompts/openspec-*.prompt` files with MARKDOWN frontmatter and `$ARGUMENTS` placeholder, and refresh them on `openspec update`. - Add Antigravity slash command support so `openspec init` can generate `.agent/workflows/openspec-*.md` files with description-only frontmatter and `openspec update` refreshes existing workflows alongside Windsurf. ## 0.15.0 ### Minor Changes - 4758c5c: Add support for new AI tools with native slash command integration - **Gemini CLI**: Add native TOML-based slash command support for Gemini CLI with `.gemini/commands/openspec/` integration - **RooCode**: Add RooCode integration with configurator, slash commands, and templates - **Cline**: Fix Cline to use workflows instead of rules for slash commands (`.clinerules/workflows/` paths) - **Documentation**: Update documentation to reflect new integrations and workflow changes ## 0.14.0 ### Minor Changes - 8386b91: Add support for new AI assistants and configuration improvements - feat: add Qwen Code support with slash command integration - feat: add $ARGUMENTS support to apply slash command for dynamic variable passing - feat: add Qoder CLI support to configuration and documentation - feat: add CoStrict AI assistant support - fix: recreate missing openspec template files in extend mode - fix: prevent false 'already configured' detection for tools - fix: use change-id as fallback title instead of "Untitled Change" - docs: add guidance for populating project-level context - docs: add Crush to supported AI tools in README ## 0.13.0 ### Minor Changes - 668a125: Add support for multiple AI assistants and improve validation This release adds support for several new AI coding assistants: - CodeBuddy Code - AI-powered coding assistant - CodeRabbit - AI code review assistant - Cline - Claude-powered CLI assistant - Crush AI - AI assistant platform - Auggie (Augment CLI) - Code augmentation tool New features: - Archive slash command now supports arguments for more flexible workflows Bug fixes: - Delta spec validation now handles case-insensitive headers and properly detects empty sections - Archive validation now correctly honors --no-validate flag and ignores metadata Documentation improvements: - Added VS Code dev container configuration for easier development setup - Updated AGENTS.md with explicit change-id notation - Enhanced slash commands documentation with restart notes ## 0.12.0 ### Minor Changes - 082abb4: Add factory function support for slash commands and non-interactive init options This release includes two new features: - **Factory function support for slash commands**: Slash commands can now be defined as functions that return command objects, enabling dynamic command configuration - **Non-interactive init options**: Added `--tools`, `--all-tools`, and `--skip-tools` CLI flags to `openspec init` for automated initialization in CI/CD pipelines while maintaining backward compatibility with interactive mode ## 0.11.0 ### Minor Changes - 312e1d6: Add Amazon Q Developer CLI integration. OpenSpec now supports Amazon Q Developer with automatic prompt generation in `.amazonq/prompts/` directory, allowing you to use OpenSpec slash commands with Amazon Q's @-syntax. ## 0.10.0 ### Minor Changes - d7e0ce8: Improve init wizard Enter key behavior to allow proceeding through prompts more naturally ## 0.9.2 ### Patch Changes - 2ae0484: Fix cross-platform path handling issues. This release includes fixes for joinPath behavior and slash command path resolution to ensure OpenSpec works correctly across all platforms. ## 0.9.1 ### Patch Changes - 8210970: Fix OpenSpec not working on Windows when Codex integration is selected. This release includes fixes for cross-platform path handling and normalization to ensure OpenSpec works correctly on Windows systems. ## 0.9.0 ### Minor Changes - efbbf3b: Add support for Codex and GitHub Copilot slash commands with YAML frontmatter and $ARGUMENTS ## Unreleased ### Minor Changes - Add GitHub Copilot slash command support. OpenSpec now writes prompts to `.github/prompts/openspec-{proposal,apply,archive}.prompt.md` with YAML frontmatter and `$ARGUMENTS` placeholder, and refreshes them on `openspec update`. ## 0.8.1 ### Patch Changes - d070d08: Fix CLI version mismatch and add a release guard that validates the packed tarball prints the same version as package.json via `openspec --version`. ## 0.8.0 ### Minor Changes - c29b06d: Add Windsurf support. - Add Codex slash command support. OpenSpec now writes prompts directly to Codex's global directory (`~/.codex/prompts` or `$CODEX_HOME/prompts`) and refreshes them on `openspec update`. ## 0.7.0 ### Minor Changes - Add native Kilo Code workflow integration so `openspec init` and `openspec update` manage `.kilocode/workflows/openspec-*.md` files. - Always scaffold the managed root `AGENTS.md` hand-off stub and regroup the AI tool prompts during init/update to keep instructions consistent. ## 0.6.0 ### Minor Changes - Slim the generated root agent instructions down to a managed hand-off stub and update the init/update flows to refresh it safely. ## 0.5.0 ### Minor Changes - feat: implement Phase 1 E2E testing with cross-platform CI matrix - Add shared runCLI helper in test/helpers/run-cli.ts for spawn testing - Create test/cli-e2e/basic.test.ts covering help, version, validate flows - Migrate existing CLI exec tests to use runCLI helper - Extend CI matrix to bash (Linux/macOS) and pwsh (Windows) - Split PR and main workflows for optimized feedback ### Patch Changes - Make apply instructions more specific Improve agent templates and slash command templates with more specific and actionable apply instructions. - docs: improve documentation and cleanup - Document non-interactive flag for archive command - Replace discord badge in README - Archive completed changes for better organization ## 0.4.0 ### Minor Changes - Add OpenSpec change proposals for CLI improvements and enhanced user experience - Add Opencode slash commands support for AI-driven development workflows ### Patch Changes - Add documentation improvements including --yes flag for archive command template and Discord badge - Fix normalize line endings in markdown parser to handle CRLF files properly ## 0.3.0 ### Minor Changes - Enhance `openspec init` with extend mode, multi-tool selection, and an interactive `AGENTS.md` configurator. ## 0.2.0 ### Minor Changes - ce5cead: - Add an `openspec view` dashboard that rolls up spec counts and change progress at a glance - Generate and update AI slash commands alongside the renamed `openspec/AGENTS.md` instructions file - Remove the deprecated `openspec diff` command and direct users to `openspec show` ## 0.1.0 ### Minor Changes - 24b4866: Initial release ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2024 OpenSpec Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: MAINTAINERS.md ================================================ # Maintainers People who maintain and guide OpenSpec. ## Core Maintainers | Name | GitHub | Role | |------|--------|------| | Tabish Bidiwale | [@TabishB](https://github.com/TabishB) | Lead maintainer | ## Advisors Advisors help shape technical direction and provide guidance to the project. | Name | GitHub | Focus | |------|--------|-------| | Hari Krishnan | [@harikrishnan83](https://github.com/harikrishnan83) | Technical direction | ================================================ FILE: README.md ================================================

OpenSpec logo

CI npm version License: MIT Discord

The most loved spec framework. [![Stars](https://img.shields.io/github/stars/Fission-AI/OpenSpec?style=flat-square&label=Stars)](https://github.com/Fission-AI/OpenSpec/stargazers) [![Downloads](https://img.shields.io/npm/dm/@fission-ai/openspec?style=flat-square&label=Downloads/mo)](https://www.npmjs.com/package/@fission-ai/openspec) [![Contributors](https://img.shields.io/github/contributors/Fission-AI/OpenSpec?style=flat-square&label=Contributors)](https://github.com/Fission-AI/OpenSpec/graphs/contributors)

Our philosophy: ```text → fluid not rigid → iterative not waterfall → easy not complex → built for brownfield not just greenfield → scalable from personal projects to enterprises ``` > [!TIP] > **New workflow now available!** We've rebuilt OpenSpec with a new artifact-guided workflow. > > Run `/opsx:propose "your idea"` to get started. → [Learn more here](docs/opsx.md)

Follow @0xTab on X for updates · Join the OpenSpec Discord for help and questions.

### Teams Using OpenSpec in a team? [Email here](mailto:teams@openspec.dev) for access to our Slack channel. ## See it in action ```text You: /opsx:propose add-dark-mode AI: Created openspec/changes/add-dark-mode/ ✓ proposal.md — why we're doing this, what's changing ✓ specs/ — requirements and scenarios ✓ design.md — technical approach ✓ tasks.md — implementation checklist Ready for implementation! You: /opsx:apply AI: Implementing tasks... ✓ 1.1 Add theme context provider ✓ 1.2 Create toggle component ✓ 2.1 Add CSS variables ✓ 2.2 Wire up localStorage All tasks complete! You: /opsx:archive AI: Archived to openspec/changes/archive/2025-01-23-add-dark-mode/ Specs updated. Ready for the next feature. ```
OpenSpec Dashboard

OpenSpec dashboard preview

## Quick Start **Requires Node.js 20.19.0 or higher.** Install OpenSpec globally: ```bash npm install -g @fission-ai/openspec@latest ``` Then navigate to your project directory and initialize: ```bash cd your-project openspec init ``` Now tell your AI: `/opsx:propose ` If you want the expanded workflow (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:sync`, `/opsx:bulk-archive`, `/opsx:onboard`), select it with `openspec config profile` and apply with `openspec update`. > [!NOTE] > Not sure if your tool is supported? [View the full list](docs/supported-tools.md) – we support 20+ tools and growing. > > Also works with pnpm, yarn, bun, and nix. [See installation options](docs/installation.md). ## Docs → **[Getting Started](docs/getting-started.md)**: first steps
→ **[Workflows](docs/workflows.md)**: combos and patterns
→ **[Commands](docs/commands.md)**: slash commands & skills
→ **[CLI](docs/cli.md)**: terminal reference
→ **[Supported Tools](docs/supported-tools.md)**: tool integrations & install paths
→ **[Concepts](docs/concepts.md)**: how it all fits
→ **[Multi-Language](docs/multi-language.md)**: multi-language support
→ **[Customization](docs/customization.md)**: make it yours ## Why OpenSpec? AI coding assistants are powerful but unpredictable when requirements live only in chat history. OpenSpec adds a lightweight spec layer so you agree on what to build before any code is written. - **Agree before you build** — human and AI align on specs before code gets written - **Stay organized** — each change gets its own folder with proposal, specs, design, and tasks - **Work fluidly** — update any artifact anytime, no rigid phase gates - **Use your tools** — works with 20+ AI assistants via slash commands ### How we compare **vs. [Spec Kit](https://github.com/github/spec-kit)** (GitHub) — Thorough but heavyweight. Rigid phase gates, lots of Markdown, Python setup. OpenSpec is lighter and lets you iterate freely. **vs. [Kiro](https://kiro.dev)** (AWS) — Powerful but you're locked into their IDE and limited to Claude models. OpenSpec works with the tools you already use. **vs. nothing** — AI coding without specs means vague prompts and unpredictable results. OpenSpec brings predictability without the ceremony. ## Updating OpenSpec **Upgrade the package** ```bash npm install -g @fission-ai/openspec@latest ``` **Refresh agent instructions** Run this inside each project to regenerate AI guidance and ensure the latest slash commands are active: ```bash openspec update ``` ## Usage Notes **Model selection**: OpenSpec works best with high-reasoning models. We recommend Opus 4.5 and GPT 5.2 for both planning and implementation. **Context hygiene**: OpenSpec benefits from a clean context window. Clear your context before starting implementation and maintain good context hygiene throughout your session. ## Contributing **Small fixes** — Bug fixes, typo corrections, and minor improvements can be submitted directly as PRs. **Larger changes** — For new features, significant refactors, or architectural changes, please submit an OpenSpec change proposal first so we can align on intent and goals before implementation begins. When writing proposals, keep the OpenSpec philosophy in mind: we serve a wide variety of users across different coding agents, models, and use cases. Changes should work well for everyone. **AI-generated code is welcome** — as long as it's been tested and verified. PRs containing AI-generated code should mention the coding agent and model used (e.g., "Generated with Claude Code using claude-opus-4-5-20251101"). ### Development - Install dependencies: `pnpm install` - Build: `pnpm run build` - Test: `pnpm test` - Develop CLI locally: `pnpm run dev` or `pnpm run dev:cli` - Conventional commits (one-line): `type(scope): subject` ## Other
Telemetry OpenSpec collects anonymous usage stats. We collect only command names and version to understand usage patterns. No arguments, paths, content, or PII. Automatically disabled in CI. **Opt-out:** `export OPENSPEC_TELEMETRY=0` or `export DO_NOT_TRACK=1`
Maintainers & Advisors See [MAINTAINERS.md](MAINTAINERS.md) for the list of core maintainers and advisors who help guide the project.
## License MIT ================================================ FILE: README_OLD.md ================================================

OpenSpec logo

Spec-driven development for AI coding assistants.

CI npm version node version License: MIT Conventional Commits Discord

OpenSpec dashboard preview

Follow @0xTab on X for updates · Join the OpenSpec Discord for help and questions.

🧪 New: OPSX Workflow — schema-driven, hackable, fluid. Iterate on workflows without code changes.

# OpenSpec OpenSpec aligns humans and AI coding assistants with spec-driven development so you agree on what to build before any code is written. **No API keys required.** ## Why OpenSpec? AI coding assistants are powerful but unpredictable when requirements live in chat history. OpenSpec adds a lightweight specification workflow that locks intent before implementation, giving you deterministic, reviewable outputs. Key outcomes: - Human and AI stakeholders agree on specs before work begins. - Structured change folders (proposals, tasks, and spec updates) keep scope explicit and auditable. - Shared visibility into what's proposed, active, or archived. - Works with the AI tools you already use: custom slash commands where supported, context rules everywhere else. ## How OpenSpec compares (at a glance) - **Lightweight**: simple workflow, no API keys, minimal setup. - **Brownfield-first**: works great beyond 0→1. OpenSpec separates the source of truth from proposals: `openspec/specs/` (current truth) and `openspec/changes/` (proposed updates). This keeps diffs explicit and manageable across features. - **Change tracking**: proposals, tasks, and spec deltas live together; archiving merges the approved updates back into specs. - **Compared to spec-kit & Kiro**: those shine for brand-new features (0→1). OpenSpec also excels when modifying existing behavior (1→n), especially when updates span multiple specs. See the full comparison in [How OpenSpec Compares](#how-openspec-compares). ## How It Works ``` ┌────────────────────┐ │ Draft Change │ │ Proposal │ └────────┬───────────┘ │ share intent with your AI ▼ ┌────────────────────┐ │ Review & Align │ │ (edit specs/tasks) │◀──── feedback loop ──────┐ └────────┬───────────┘ │ │ approved plan │ ▼ │ ┌────────────────────┐ │ │ Implement Tasks │──────────────────────────┘ │ (AI writes code) │ └────────┬───────────┘ │ ship the change ▼ ┌────────────────────┐ │ Archive & Update │ │ Specs (source) │ └────────────────────┘ 1. Draft a change proposal that captures the spec updates you want. 2. Review the proposal with your AI assistant until everyone agrees. 3. Implement tasks that reference the agreed specs. 4. Archive the change to merge the approved updates back into the source-of-truth specs. ``` ## Getting Started ### Supported AI Tools
Native Slash Commands (click to expand) These tools have built-in OpenSpec commands. Select the OpenSpec integration when prompted. | Tool | Commands | |------|----------| | **Amazon Q Developer** | `@openspec-proposal`, `@openspec-apply`, `@openspec-archive` (`.amazonq/prompts/`) | | **Antigravity** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.agent/workflows/`) | | **Auggie (Augment CLI)** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.augment/commands/`) | | **Claude Code** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` | | **Cline** | Workflows in `.clinerules/workflows/` directory (`.clinerules/workflows/openspec-*.md`) | | **CodeBuddy Code (CLI)** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.codebuddy/commands/`) — see [docs](https://www.codebuddy.ai/cli) | | **Codex** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (global: `~/.codex/prompts`, auto-installed) | | **Continue** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.continue/prompts/`) | | **CoStrict** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.cospec/openspec/commands/`) — see [docs](https://costrict.ai)| | **Crush** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.crush/commands/openspec/`) | | **Cursor** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` | | **Factory Droid** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.factory/commands/`) | | **Gemini CLI** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.gemini/commands/openspec/`) | | **GitHub Copilot** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.github/prompts/`) | | **iFlow (iflow-cli)** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.iflow/commands/`) | | **Kilo Code** | `/openspec-proposal.md`, `/openspec-apply.md`, `/openspec-archive.md` (`.kilocode/workflows/`) | | **OpenCode** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` | | **Qoder** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.qoder/commands/openspec/`) — see [docs](https://qoder.com) | | **Qwen Code** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.qwen/commands/`) | | **RooCode** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.roo/commands/`) | | **Windsurf** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.windsurf/workflows/`) | Kilo Code discovers team workflows automatically. Save the generated files under `.kilocode/workflows/` and trigger them from the command palette with `/openspec-proposal.md`, `/openspec-apply.md`, or `/openspec-archive.md`.
AGENTS.md Compatible (click to expand) These tools automatically read workflow instructions from `openspec/AGENTS.md`. Ask them to follow the OpenSpec workflow if they need a reminder. Learn more about the [AGENTS.md convention](https://agents.md/). | Tools | |-------| | Amp • Jules • Others |
### Install & Initialize #### Prerequisites - **Node.js >= 20.19.0** - Check your version with `node --version` #### Step 1: Install the CLI globally **Option A: Using npm** ```bash npm install -g @fission-ai/openspec@latest ``` Verify installation: ```bash openspec --version ``` **Option B: Using Nix (NixOS and Nix package manager)** Run OpenSpec directly without installation: ```bash nix run github:Fission-AI/OpenSpec -- init ``` Or install to your profile: ```bash nix profile install github:Fission-AI/OpenSpec ``` Or add to your development environment in `flake.nix`: ```nix { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; openspec.url = "github:Fission-AI/OpenSpec"; }; outputs = { nixpkgs, openspec, ... }: { devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell { buildInputs = [ openspec.packages.x86_64-linux.default ]; }; }; } ``` Verify installation: ```bash openspec --version ``` #### Step 2: Initialize OpenSpec in your project Navigate to your project directory: ```bash cd my-project ``` Run the initialization: ```bash openspec init ``` **What happens during initialization:** - You'll be prompted to pick any natively supported AI tools (Claude Code, CodeBuddy, Cursor, OpenCode, Qoder,etc.); other assistants always rely on the shared `AGENTS.md` stub - OpenSpec automatically configures slash commands for the tools you choose and always writes a managed `AGENTS.md` hand-off at the project root - A new `openspec/` directory structure is created in your project **After setup:** - Primary AI tools can trigger `/openspec` workflows without additional configuration - Run `openspec list` to verify the setup and view any active changes - If your coding assistant doesn't surface the new slash commands right away, restart it. Slash commands are loaded at startup, so a fresh launch ensures they appear ### Optional: Populate Project Context After `openspec init` completes, you'll receive a suggested prompt to help populate your project context: ```text Populate your project context: "Please read openspec/project.md and help me fill it out with details about my project, tech stack, and conventions" ``` Use `openspec/project.md` to define project-level conventions, standards, architectural patterns, and other guidelines that should be followed across all changes. ### Create Your First Change Here's a real example showing the complete OpenSpec workflow. This works with any AI tool. Those with native slash commands will recognize the shortcuts automatically. #### 1. Draft the Proposal Start by asking your AI to create a change proposal: ```text You: Create an OpenSpec change proposal for adding profile search filters by role and team (Shortcut for tools with slash commands: /openspec:proposal Add profile search filters) AI: I'll create an OpenSpec change proposal for profile filters. *Scaffolds openspec/changes/add-profile-filters/ with proposal.md, tasks.md, spec deltas.* ``` #### 2. Verify & Review Check that the change was created correctly and review the proposal: ```bash $ openspec list # Confirm the change folder exists $ openspec validate add-profile-filters # Validate spec formatting $ openspec show add-profile-filters # Review proposal, tasks, and spec delta ``` #### 3. Refine the Specs Iterate on the specifications until they match your needs: ```text You: Can you add acceptance criteria for the role and team filters? AI: I'll update the spec delta with scenarios for role and team filters. *Edits openspec/changes/add-profile-filters/specs/profile/spec.md and tasks.md.* ``` #### 4. Implement the Change Once specs look good, start implementation: ```text You: The specs look good. Let's implement this change. (Shortcut for tools with slash commands: /openspec:apply add-profile-filters) AI: I'll work through the tasks in the add-profile-filters change. *Implements tasks from openspec/changes/add-profile-filters/tasks.md* *Marks tasks complete: Task 1.1 ✓, Task 1.2 ✓, Task 2.1 ✓...* ``` #### 5. Archive the Completed Change After implementation is complete, archive the change: ```text AI: All tasks are complete. The implementation is ready. You: Please archive the change (Shortcut for tools with slash commands: /openspec:archive add-profile-filters) AI: I'll archive the add-profile-filters change. *Runs: openspec archive add-profile-filters --yes* ✓ Change archived successfully. Specs updated. Ready for the next feature! ``` Or run the command yourself in terminal: ```bash $ openspec archive add-profile-filters --yes # Archive the completed change without prompts ``` **Note:** Tools with native slash commands (Claude Code, CodeBuddy, Cursor, Codex, Qoder, RooCode) can use the shortcuts shown. All other tools work with natural language requests to "create an OpenSpec proposal", "apply the OpenSpec change", or "archive the change". ## Command Reference ```bash openspec list # View active change folders openspec view # Interactive dashboard of specs and changes openspec show # Display change details (proposal, tasks, spec updates) openspec validate # Check spec formatting and structure openspec archive [--yes|-y] # Move a completed change into archive/ (non-interactive with --yes) ``` ## Example: How AI Creates OpenSpec Files When you ask your AI assistant to "add two-factor authentication", it creates: ``` openspec/ ├── specs/ │ └── auth/ │ └── spec.md # Current auth spec (if exists) └── changes/ └── add-2fa/ # AI creates this entire structure ├── proposal.md # Why and what changes ├── tasks.md # Implementation checklist ├── design.md # Technical decisions (optional) └── specs/ └── auth/ └── spec.md # Delta showing additions ``` ### AI-Generated Spec (created in `openspec/specs/auth/spec.md`): ```markdown # Auth Specification ## Purpose Authentication and session management. ## Requirements ### Requirement: User Authentication The system SHALL issue a JWT on successful login. #### Scenario: Valid credentials - WHEN a user submits valid credentials - THEN a JWT is returned ``` ### AI-Generated Change Delta (created in `openspec/changes/add-2fa/specs/auth/spec.md`): ```markdown # Delta for Auth ## ADDED Requirements ### Requirement: Two-Factor Authentication The system MUST require a second factor during login. #### Scenario: OTP required - WHEN a user submits valid credentials - THEN an OTP challenge is required ``` ### AI-Generated Tasks (created in `openspec/changes/add-2fa/tasks.md`): ```markdown ## 1. Database Setup - [ ] 1.1 Add OTP secret column to users table - [ ] 1.2 Create OTP verification logs table ## 2. Backend Implementation - [ ] 2.1 Add OTP generation endpoint - [ ] 2.2 Modify login flow to require OTP - [ ] 2.3 Add OTP verification endpoint ## 3. Frontend Updates - [ ] 3.1 Create OTP input component - [ ] 3.2 Update login flow UI ``` **Important:** You don't create these files manually. Your AI assistant generates them based on your requirements and the existing codebase. ## Understanding OpenSpec Files ### Delta Format Deltas are "patches" that show how specs change: - **`## ADDED Requirements`** - New capabilities - **`## MODIFIED Requirements`** - Changed behavior (include complete updated text) - **`## REMOVED Requirements`** - Deprecated features **Format requirements:** - Use `### Requirement: ` for headers - Every requirement needs at least one `#### Scenario:` block - Use SHALL/MUST in requirement text ## How OpenSpec Compares ### vs. spec-kit OpenSpec’s two-folder model (`openspec/specs/` for the current truth, `openspec/changes/` for proposed updates) keeps state and diffs separate. This scales when you modify existing features or touch multiple specs. spec-kit is strong for greenfield/0→1 but provides less structure for cross-spec updates and evolving features. ### vs. Kiro.dev OpenSpec groups every change for a feature in one folder (`openspec/changes/feature-name/`), making it easy to track related specs, tasks, and designs together. Kiro spreads updates across multiple spec folders, which can make feature tracking harder. ### vs. No Specs Without specs, AI coding assistants generate code from vague prompts, often missing requirements or adding unwanted features. OpenSpec brings predictability by agreeing on the desired behavior before any code is written. ## Team Adoption 1. **Initialize OpenSpec** – Run `openspec init` in your repo. 2. **Start with new features** – Ask your AI to capture upcoming work as change proposals. 3. **Grow incrementally** – Each change archives into living specs that document your system. 4. **Stay flexible** – Different teammates can use Claude Code, CodeBuddy, Cursor, or any AGENTS.md-compatible tool while sharing the same specs. Run `openspec update` whenever someone switches tools so your agents pick up the latest instructions and slash-command bindings. ## Updating OpenSpec 1. **Upgrade the package** ```bash npm install -g @fission-ai/openspec@latest ``` 2. **Refresh agent instructions** - Run `openspec update` inside each project to regenerate AI guidance and ensure the latest slash commands are active. ## Experimental Features
🧪 OPSX: Fluid, Iterative Workflow (Claude Code only) **Why this exists:** - Standard workflow is locked down — you can't tweak instructions or customize - When AI output is bad, you can't improve the prompts yourself - Same workflow for everyone, no way to match how your team works **What's different:** - **Hackable** — edit templates and schemas yourself, test immediately, no rebuild - **Granular** — each artifact has its own instructions, test and tweak individually - **Customizable** — define your own workflows, artifacts, and dependencies - **Fluid** — no phase gates, update any artifact anytime ``` You can always go back: proposal ──→ specs ──→ design ──→ tasks ──→ implement ▲ ▲ ▲ │ └───────────┴──────────┴────────────────────┘ ``` | Command | What it does | |---------|--------------| | `/opsx:new` | Start a new change | | `/opsx:continue` | Create the next artifact (based on what's ready) | | `/opsx:ff` | Fast-forward (all planning artifacts at once) | | `/opsx:apply` | Implement tasks, updating artifacts as needed | | `/opsx:archive` | Archive when done | **Setup:** `openspec experimental` [Full documentation →](docs/opsx.md)
Telemetry – OpenSpec collects anonymous usage stats (opt-out: OPENSPEC_TELEMETRY=0) We collect only command names and version to understand usage patterns. No arguments, paths, content, or PII. Automatically disabled in CI. **Opt-out:** `export OPENSPEC_TELEMETRY=0` or `export DO_NOT_TRACK=1`
## Contributing - Install dependencies: `pnpm install` - Build: `pnpm run build` - Test: `pnpm test` - Develop CLI locally: `pnpm run dev` or `pnpm run dev:cli` - Conventional commits (one-line): `type(scope): subject`
Maintainers & Advisors See [MAINTAINERS.md](MAINTAINERS.md) for the list of core maintainers and advisors who help guide the project.
## License MIT ================================================ FILE: bin/openspec.js ================================================ #!/usr/bin/env node import '../dist/cli/index.js'; ================================================ FILE: build.js ================================================ #!/usr/bin/env node import { execFileSync } from 'child_process'; import { existsSync, rmSync } from 'fs'; import { createRequire } from 'module'; const require = createRequire(import.meta.url); const runTsc = (args = []) => { const tscPath = require.resolve('typescript/bin/tsc'); execFileSync(process.execPath, [tscPath, ...args], { stdio: 'inherit' }); }; console.log('🔨 Building OpenSpec...\n'); // Clean dist directory if (existsSync('dist')) { console.log('Cleaning dist directory...'); rmSync('dist', { recursive: true, force: true }); } // Run TypeScript compiler (use local version explicitly) console.log('Compiling TypeScript...'); try { runTsc(['--version']); runTsc(); console.log('\n✅ Build completed successfully!'); } catch (error) { console.error('\n❌ Build failed!'); process.exit(1); } ================================================ FILE: docs/cli.md ================================================ # CLI Reference The OpenSpec CLI (`openspec`) provides terminal commands for project setup, validation, status inspection, and management. These commands complement the AI slash commands (like `/opsx:propose`) documented in [Commands](commands.md). ## Summary | Category | Commands | Purpose | |----------|----------|---------| | **Setup** | `init`, `update` | Initialize and update OpenSpec in your project | | **Browsing** | `list`, `view`, `show` | Explore changes and specs | | **Validation** | `validate` | Check changes and specs for issues | | **Lifecycle** | `archive` | Finalize completed changes | | **Workflow** | `status`, `instructions`, `templates`, `schemas` | Artifact-driven workflow support | | **Schemas** | `schema init`, `schema fork`, `schema validate`, `schema which` | Create and manage custom workflows | | **Config** | `config` | View and modify settings | | **Utility** | `feedback`, `completion` | Feedback and shell integration | --- ## Human vs Agent Commands Most CLI commands are designed for **human use** in a terminal. Some commands also support **agent/script use** via JSON output. ### Human-Only Commands These commands are interactive and designed for terminal use: | Command | Purpose | |---------|---------| | `openspec init` | Initialize project (interactive prompts) | | `openspec view` | Interactive dashboard | | `openspec config edit` | Open config in editor | | `openspec feedback` | Submit feedback via GitHub | | `openspec completion install` | Install shell completions | ### Agent-Compatible Commands These commands support `--json` output for programmatic use by AI agents and scripts: | Command | Human Use | Agent Use | |---------|-----------|-----------| | `openspec list` | Browse changes/specs | `--json` for structured data | | `openspec show ` | Read content | `--json` for parsing | | `openspec validate` | Check for issues | `--all --json` for bulk validation | | `openspec status` | See artifact progress | `--json` for structured status | | `openspec instructions` | Get next steps | `--json` for agent instructions | | `openspec templates` | Find template paths | `--json` for path resolution | | `openspec schemas` | List available schemas | `--json` for schema discovery | --- ## Global Options These options work with all commands: | Option | Description | |--------|-------------| | `--version`, `-V` | Show version number | | `--no-color` | Disable color output | | `--help`, `-h` | Display help for command | --- ## Setup Commands ### `openspec init` 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] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `path` | No | Target directory (default: current directory) | **Options:** | Option | Description | |--------|-------------| | `--tools ` | Configure AI tools non-interactively. Use `all`, `none`, or comma-separated list | | `--force` | Auto-cleanup legacy files without prompting | | `--profile ` | Override global profile for this init run (`core` or `custom`) | `--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:** ```bash # Interactive initialization openspec init # Initialize in a specific directory openspec init ./my-project # Non-interactive: configure for Claude and Cursor 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 ``` **What it creates:** ``` openspec/ ├── specs/ # Your specifications (source of truth) ├── changes/ # Proposed changes └── config.yaml # Project configuration .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) ``` --- ### `openspec update` 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] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `path` | No | Target directory (default: current directory) | **Options:** | Option | Description | |--------|-------------| | `--force` | Force update even when files are up to date | **Example:** ```bash # Update instruction files after npm upgrade npm update @fission-ai/openspec openspec update ``` --- ## Browsing Commands ### `openspec list` List changes or specs in your project. ``` openspec list [options] ``` **Options:** | Option | Description | |--------|-------------| | `--specs` | List specs instead of changes | | `--changes` | List changes (default) | | `--sort ` | Sort by `recent` (default) or `name` | | `--json` | Output as JSON | **Examples:** ```bash # List all active changes openspec list # List all specs openspec list --specs # JSON output for scripts openspec list --json ``` **Output (text):** ``` Active changes: add-dark-mode UI theme switching support fix-login-bug Session timeout handling ``` --- ### `openspec view` Display an interactive dashboard for exploring specs and changes. ``` openspec view ``` Opens a terminal-based interface for navigating your project's specifications and changes. --- ### `openspec show` Display details of a change or spec. ``` openspec show [item-name] [options] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `item-name` | No | Name of change or spec (prompts if omitted) | **Options:** | Option | Description | |--------|-------------| | `--type ` | Specify type: `change` or `spec` (auto-detected if unambiguous) | | `--json` | Output as JSON | | `--no-interactive` | Disable prompts | **Change-specific options:** | Option | Description | |--------|-------------| | `--deltas-only` | Show only delta specs (JSON mode) | **Spec-specific options:** | Option | Description | |--------|-------------| | `--requirements` | Show only requirements, exclude scenarios (JSON mode) | | `--no-scenarios` | Exclude scenario content (JSON mode) | | `-r, --requirement ` | Show specific requirement by 1-based index (JSON mode) | **Examples:** ```bash # Interactive selection openspec show # Show a specific change openspec show add-dark-mode # Show a specific spec openspec show auth --type spec # JSON output for parsing openspec show add-dark-mode --json ``` --- ## Validation Commands ### `openspec validate` Validate changes and specs for structural issues. ``` openspec validate [item-name] [options] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `item-name` | No | Specific item to validate (prompts if omitted) | **Options:** | Option | Description | |--------|-------------| | `--all` | Validate all changes and specs | | `--changes` | Validate all changes | | `--specs` | Validate all specs | | `--type ` | Specify type when name is ambiguous: `change` or `spec` | | `--strict` | Enable strict validation mode | | `--json` | Output as JSON | | `--concurrency ` | Max parallel validations (default: 6, or `OPENSPEC_CONCURRENCY` env) | | `--no-interactive` | Disable prompts | **Examples:** ```bash # Interactive validation openspec validate # Validate a specific change openspec validate add-dark-mode # Validate all changes openspec validate --changes # Validate everything with JSON output (for CI/scripts) openspec validate --all --json # Strict validation with increased parallelism openspec validate --all --strict --concurrency 12 ``` **Output (text):** ``` Validating add-dark-mode... ✓ proposal.md valid ✓ specs/ui/spec.md valid ⚠ design.md: missing "Technical Approach" section 1 warning found ``` **Output (JSON):** ```json { "version": "1.0.0", "results": { "changes": [ { "name": "add-dark-mode", "valid": true, "warnings": ["design.md: missing 'Technical Approach' section"] } ] }, "summary": { "total": 1, "valid": 1, "invalid": 0 } } ``` --- ## Lifecycle Commands ### `openspec archive` Archive a completed change and merge delta specs into main specs. ``` openspec archive [change-name] [options] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `change-name` | No | Change to archive (prompts if omitted) | **Options:** | Option | Description | |--------|-------------| | `-y, --yes` | Skip confirmation prompts | | `--skip-specs` | Skip spec updates (for infrastructure/tooling/doc-only changes) | | `--no-validate` | Skip validation (requires confirmation) | **Examples:** ```bash # Interactive archive openspec archive # Archive specific change openspec archive add-dark-mode # Archive without prompts (CI/scripts) openspec archive add-dark-mode --yes # Archive a tooling change that doesn't affect specs openspec archive update-ci-config --skip-specs ``` **What it does:** 1. Validates the change (unless `--no-validate`) 2. Prompts for confirmation (unless `--yes`) 3. Merges delta specs into `openspec/specs/` 4. Moves change folder to `openspec/changes/archive/YYYY-MM-DD-/` --- ## Workflow Commands These commands support the artifact-driven OPSX workflow. They're useful for both humans checking progress and agents determining next steps. ### `openspec status` Display artifact completion status for a change. ``` openspec status [options] ``` **Options:** | Option | Description | |--------|-------------| | `--change ` | Change name (prompts if omitted) | | `--schema ` | Schema override (auto-detected from change's config) | | `--json` | Output as JSON | **Examples:** ```bash # Interactive status check openspec status # Status for specific change openspec status --change add-dark-mode # JSON for agent use openspec status --change add-dark-mode --json ``` **Output (text):** ``` Change: add-dark-mode Schema: spec-driven Progress: 2/4 artifacts complete [x] proposal [ ] design [x] specs [-] tasks (blocked by: design) ``` **Output (JSON):** ```json { "changeName": "add-dark-mode", "schemaName": "spec-driven", "isComplete": false, "applyRequires": ["tasks"], "artifacts": [ {"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"]} ] } ``` --- ### `openspec instructions` Get enriched instructions for creating an artifact or applying tasks. Used by AI agents to understand what to create next. ``` openspec instructions [artifact] [options] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `artifact` | No | Artifact ID: `proposal`, `specs`, `design`, `tasks`, or `apply` | **Options:** | Option | Description | |--------|-------------| | `--change ` | Change name (required in non-interactive mode) | | `--schema ` | Schema override | | `--json` | Output as JSON | **Special case:** Use `apply` as the artifact to get task implementation instructions. **Examples:** ```bash # Get instructions for next artifact openspec instructions --change add-dark-mode # Get specific artifact instructions openspec instructions design --change add-dark-mode # Get apply/implementation instructions openspec instructions apply --change add-dark-mode # JSON for agent consumption openspec instructions design --change add-dark-mode --json ``` **Output includes:** - Template content for the artifact - Project context from config - Content from dependency artifacts - Per-artifact rules from config --- ### `openspec templates` Show resolved template paths for all artifacts in a schema. ``` openspec templates [options] ``` **Options:** | Option | Description | |--------|-------------| | `--schema ` | Schema to inspect (default: `spec-driven`) | | `--json` | Output as JSON | **Examples:** ```bash # Show template paths for default schema openspec templates # Show templates for custom schema openspec templates --schema my-workflow # JSON for programmatic use openspec templates --json ``` **Output (text):** ``` Schema: spec-driven Templates: proposal → ~/.openspec/schemas/spec-driven/templates/proposal.md specs → ~/.openspec/schemas/spec-driven/templates/specs.md design → ~/.openspec/schemas/spec-driven/templates/design.md tasks → ~/.openspec/schemas/spec-driven/templates/tasks.md ``` --- ### `openspec schemas` List available workflow schemas with their descriptions and artifact flows. ``` openspec schemas [options] ``` **Options:** | Option | Description | |--------|-------------| | `--json` | Output as JSON | **Example:** ```bash openspec schemas ``` **Output:** ``` Available schemas: spec-driven (package) The default spec-driven development workflow Flow: proposal → specs → design → tasks my-custom (project) Custom workflow for this project Flow: research → proposal → tasks ``` --- ## Schema Commands Commands for creating and managing custom workflow schemas. ### `openspec schema init` Create a new project-local schema. ``` openspec schema init [options] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `name` | Yes | Schema name (kebab-case) | **Options:** | Option | Description | |--------|-------------| | `--description ` | Schema description | | `--artifacts ` | Comma-separated artifact IDs (default: `proposal,specs,design,tasks`) | | `--default` | Set as project default schema | | `--no-default` | Don't prompt to set as default | | `--force` | Overwrite existing schema | | `--json` | Output as JSON | **Examples:** ```bash # Interactive schema creation openspec schema init research-first # Non-interactive with specific artifacts openspec schema init rapid \ --description "Rapid iteration workflow" \ --artifacts "proposal,tasks" \ --default ``` **What it creates:** ``` openspec/schemas// ├── schema.yaml # Schema definition └── templates/ ├── proposal.md # Template for each artifact ├── specs.md ├── design.md └── tasks.md ``` --- ### `openspec schema fork` Copy an existing schema to your project for customization. ``` openspec schema fork [name] [options] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `source` | Yes | Schema to copy | | `name` | No | New schema name (default: `-custom`) | **Options:** | Option | Description | |--------|-------------| | `--force` | Overwrite existing destination | | `--json` | Output as JSON | **Example:** ```bash # Fork the built-in spec-driven schema openspec schema fork spec-driven my-workflow ``` --- ### `openspec schema validate` Validate a schema's structure and templates. ``` openspec schema validate [name] [options] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `name` | No | Schema to validate (validates all if omitted) | **Options:** | Option | Description | |--------|-------------| | `--verbose` | Show detailed validation steps | | `--json` | Output as JSON | **Example:** ```bash # Validate a specific schema openspec schema validate my-workflow # Validate all schemas openspec schema validate ``` --- ### `openspec schema which` Show where a schema resolves from (useful for debugging precedence). ``` openspec schema which [name] [options] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `name` | No | Schema name | **Options:** | Option | Description | |--------|-------------| | `--all` | List all schemas with their sources | | `--json` | Output as JSON | **Example:** ```bash # Check where a schema comes from openspec schema which spec-driven ``` **Output:** ``` spec-driven resolves from: package Source: /usr/local/lib/node_modules/@fission-ai/openspec/schemas/spec-driven ``` **Schema precedence:** 1. Project: `openspec/schemas//` 2. User: `~/.local/share/openspec/schemas//` 3. Package: Built-in schemas --- ## Configuration Commands ### `openspec config` View and modify global OpenSpec configuration. ``` openspec config [options] ``` **Subcommands:** | Subcommand | Description | |------------|-------------| | `path` | Show config file location | | `list` | Show all current settings | | `get ` | Get a specific value | | `set ` | Set a value | | `unset ` | Remove a key | | `reset` | Reset to defaults | | `edit` | Open in `$EDITOR` | | `profile [preset]` | Configure workflow profile interactively or via preset | **Examples:** ```bash # Show config file path openspec config path # List all settings openspec config list # Get a specific value openspec config get telemetry.enabled # Set a value openspec config set telemetry.enabled false # Set a string value explicitly openspec config set user.name "My Name" --string # Remove a custom setting openspec config unset user.name # Reset all configuration 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 ``` --- ## Utility Commands ### `openspec feedback` Submit feedback about OpenSpec. Creates a GitHub issue. ``` openspec feedback [options] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `message` | Yes | Feedback message | **Options:** | Option | Description | |--------|-------------| | `--body ` | Detailed description | **Requirements:** GitHub CLI (`gh`) must be installed and authenticated. **Example:** ```bash openspec feedback "Add support for custom artifact types" \ --body "I'd like to define my own artifact types beyond the built-in ones." ``` --- ### `openspec completion` Manage shell completions for the OpenSpec CLI. ``` openspec completion [shell] ``` **Subcommands:** | Subcommand | Description | |------------|-------------| | `generate [shell]` | Output completion script to stdout | | `install [shell]` | Install completion for your shell | | `uninstall [shell]` | Remove installed completions | **Supported shells:** `bash`, `zsh`, `fish`, `powershell` **Examples:** ```bash # Install completions (auto-detects shell) openspec completion install # Install for specific shell openspec completion install zsh # Generate script for manual installation openspec completion generate bash > ~/.bash_completion.d/openspec # Uninstall openspec completion uninstall ``` --- ## Exit Codes | Code | Meaning | |------|---------| | `0` | Success | | `1` | Error (validation failure, missing files, etc.) | --- ## Environment Variables | Variable | Description | |----------|-------------| | `OPENSPEC_CONCURRENCY` | Default concurrency for bulk validation (default: 6) | | `EDITOR` or `VISUAL` | Editor for `openspec config edit` | | `NO_COLOR` | Disable color output when set | --- ## Related Documentation - [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 ================================================ FILE: docs/commands.md ================================================ # Commands This is the reference for OpenSpec's slash commands. These commands are invoked in your AI coding assistant's chat interface (e.g., Claude Code, Cursor, Windsurf). For workflow patterns and when to use each command, see [Workflows](workflows.md). For CLI commands, see [CLI](cli.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: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:verify` | Validate implementation matches artifacts | | `/opsx:sync` | Merge delta specs into main specs | | `/opsx:bulk-archive` | Archive multiple changes at once | | `/opsx:onboard` | Guided tutorial through the complete workflow | 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//` - 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. **Syntax:** ``` /opsx:explore [topic] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `topic` | No | What you want to explore or investigate | **What it does:** - Opens an exploratory conversation with no structure required - Investigates the codebase to answer questions - Compares options and approaches - Creates visual diagrams to clarify thinking - Can transition to `/opsx:propose` (default) or `/opsx:new` (expanded workflow) when insights crystallize **Example:** ```text You: /opsx:explore AI: What would you like to explore? You: How should we handle authentication for the mobile app? AI: Let me investigate your current auth setup... [Analyzes codebase] I see you're using session-based auth for the web app. For mobile, we have three main options: 1. JWT tokens (stateless, works offline) 2. OAuth2 (if you need third-party login) 3. Extend current sessions (simpler, but requires connectivity) Your API already has CORS configured. Which direction interests you? You: Let's go with JWT. Can we start a change for that? AI: Ready when you are. Run /opsx:propose add-jwt-auth to begin. ``` **Tips:** - Use when requirements are unclear or you need to investigate - No artifacts are created during exploration - Good for comparing multiple approaches before deciding - Can read files and search the codebase --- ### `/opsx:new` 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:** ``` /opsx:new [change-name] [--schema ] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `change-name` | No | Name for the change folder (prompted if not provided) | | `--schema` | No | Workflow schema to use (default: from config or `spec-driven`) | **What it does:** - Creates `openspec/changes//` directory - Creates `.openspec.yaml` metadata file in the change folder - Shows the first artifact template ready for creation - Prompts for change name and schema if not provided **What it creates:** ``` openspec/changes// └── .openspec.yaml # Change metadata (schema, created date) ``` **Example:** ``` You: /opsx:new add-dark-mode AI: Created openspec/changes/add-dark-mode/ Schema: spec-driven Ready to create: proposal Use /opsx:continue to create it, or /opsx:ff to create all artifacts. ``` **Tips:** - Use descriptive names: `add-feature`, `fix-bug`, `refactor-module` - Avoid generic names like `update`, `changes`, `wip` - Schema can also be set in project config (`openspec/config.yaml`) --- ### `/opsx:continue` Create the next artifact in the dependency chain. Creates one artifact at a time for incremental progress. **Syntax:** ``` /opsx:continue [change-name] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `change-name` | No | Which change to continue (inferred from context if not provided) | **What it does:** - Queries the artifact dependency graph - Shows which artifacts are ready vs blocked - Creates the first ready artifact - Reads dependency files for context - Shows what becomes available after creation **Example:** ``` You: /opsx:continue AI: Change: add-dark-mode Artifact status: ✓ proposal (done) ◆ specs (ready) ◆ design (ready) ○ tasks (blocked - needs: specs) Creating specs... [Reads proposal.md, creates specs based on requirements] ✓ Created openspec/changes/add-dark-mode/specs/ui/spec.md Now available: tasks Run /opsx:continue to create the next artifact. ``` **Tips:** - Use when you want to review each artifact before proceeding - Good for complex changes where you want control - Multiple artifacts may become ready simultaneously - You can edit created artifacts before continuing --- ### `/opsx:ff` Fast-forward through artifact creation. Creates all planning artifacts at once. **Syntax:** ``` /opsx:ff [change-name] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `change-name` | No | Which change to fast-forward (inferred from context if not provided) | **What it does:** - Creates all artifacts in dependency order - Tracks progress via todo list - Stops when all `apply-required` artifacts are complete - Reads each dependency before creating the next artifact **Example:** ``` You: /opsx:ff add-dark-mode AI: Fast-forwarding add-dark-mode... ✓ Creating proposal.md ✓ Creating specs/ui/spec.md ✓ Creating design.md ✓ Creating tasks.md All planning artifacts complete! Ready for implementation. Run /opsx:apply to begin. ``` **Tips:** - Use when you have a clear picture of what you're building - Faster than `/opsx:continue` for straightforward changes - You can still edit artifacts afterward - Good for small to medium features --- ### `/opsx:apply` Implement tasks from the change. Works through the task list, writing code and checking off items. **Syntax:** ``` /opsx:apply [change-name] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `change-name` | No | Which change to implement (inferred from context if not provided) | **What it does:** - Reads `tasks.md` and identifies incomplete tasks - Works through tasks one by one - Writes code, creates files, runs tests as needed - Marks tasks complete with checkboxes `[x]` **Example:** ``` You: /opsx:apply AI: Implementing add-dark-mode... Reading tasks.md: - [ ] 1.1 Create ThemeContext - [ ] 1.2 Add CSS custom properties - [ ] 1.3 Implement localStorage persistence Working on 1.1: Create ThemeContext... [Creates src/context/ThemeContext.tsx] ✓ 1.1 Complete Working on 1.2: Add CSS custom properties... [Updates src/styles/globals.css] ✓ 1.2 Complete ... ``` **Tips:** - Can resume where you left off if interrupted - Use for parallel changes by specifying the change name - Completion state is tracked in `tasks.md` checkboxes --- ### `/opsx:verify` Validate that implementation matches your change artifacts. Checks completeness, correctness, and coherence. **Syntax:** ``` /opsx:verify [change-name] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `change-name` | No | Which change to verify (inferred from context if not provided) | **What it does:** - Checks three dimensions of implementation quality - Searches codebase for implementation evidence - Reports issues categorized as CRITICAL, WARNING, or SUGGESTION - Does not block archive, but surfaces issues **Verification dimensions:** | Dimension | What it validates | |-----------|-------------------| | **Completeness** | All tasks done, all requirements implemented, scenarios covered | | **Correctness** | Implementation matches spec intent, edge cases handled | | **Coherence** | Design decisions reflected in code, patterns consistent | **Example:** ``` You: /opsx:verify AI: Verifying add-dark-mode... COMPLETENESS ✓ All 8 tasks in tasks.md are checked ✓ All requirements in specs have corresponding code ⚠ Scenario "System preference detection" has no test coverage CORRECTNESS ✓ Implementation matches spec intent ✓ Edge cases from scenarios are handled ✓ Error states match spec definitions COHERENCE ✓ Design decisions reflected in code structure ✓ Naming conventions consistent with design.md ⚠ Design mentions "CSS variables" but implementation uses Tailwind classes SUMMARY ───────────────────────────── Critical issues: 0 Warnings: 2 Ready to archive: Yes (with warnings) Recommendations: 1. Add test for system preference detection 2. Update design.md to reflect Tailwind usage, or refactor to use CSS variables ``` **Tips:** - Run before archiving to catch mismatches early - Warnings don't block archive but indicate potential issues - Good for reviewing AI's work before committing - Can reveal drift between artifacts and implementation --- ### `/opsx:sync` **Optional command.** Merge delta specs from a change into main specs. Archive will prompt to sync if needed, so you typically don't need to run this manually. **Syntax:** ``` /opsx:sync [change-name] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `change-name` | No | Which change to sync (inferred from context if not provided) | **What it does:** - Reads delta specs from change folder - Parses ADDED/MODIFIED/REMOVED/RENAMED sections - Merges changes into main `openspec/specs/` directory - Preserves existing content not mentioned in delta - Does not archive the change (remains active) **Example:** ```text You: /opsx:sync AI: Syncing add-dark-mode delta specs... Reading: openspec/changes/add-dark-mode/specs/ui/spec.md Target: openspec/specs/ui/spec.md Changes to apply: ✓ ADDED: Theme Selection requirement (2 scenarios) ✓ ADDED: Accessibility requirement (1 scenario) Merging... ✓ openspec/specs/ui/spec.md updated Change remains active. Run /opsx:archive when ready to complete. ``` **When to use manually:** | Scenario | Use sync? | |----------|-----------| | Long-running change, want specs in main before archiving | Yes | | Multiple parallel changes need the updated base specs | Yes | | Want to preview/review the merge separately | Yes | | Quick change, going straight to archive | No (archive handles it) | **Tips:** - Sync is intelligent, not copy-paste - Can add scenarios to existing requirements without duplicating - Change stays active after sync (not archived) - Most users will never need to call this directly—archive prompts if needed --- ### `/opsx:archive` Archive a completed change. Finalizes the change and moves it to the archive folder. **Syntax:** ``` /opsx:archive [change-name] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `change-name` | No | Which change to archive (inferred from context if not provided) | **What it does:** - Checks artifact completion status - Checks task completion (warns if incomplete) - Offers to sync delta specs if not already synced - Moves change folder to `openspec/changes/archive/YYYY-MM-DD-/` - Preserves all artifacts for audit trail **Example:** ```text You: /opsx:archive AI: Archiving add-dark-mode... Artifact status: ✓ proposal.md exists ✓ specs/ exists ✓ design.md exists ✓ tasks.md exists (8/8 tasks complete) Delta specs: Not yet synced → Sync now? (recommended) You: Yes AI: ✓ Synced specs to openspec/specs/ui/spec.md ✓ Moved to openspec/changes/archive/2025-01-24-add-dark-mode/ Change archived successfully. ``` **Tips:** - Archive won't block on incomplete tasks, but will warn - Delta specs can be synced during archive or beforehand - Archived changes are preserved for history - Use `/opsx:verify` first to catch issues --- ### `/opsx:bulk-archive` Archive multiple completed changes at once. Handles spec conflicts between changes. **Syntax:** ``` /opsx:bulk-archive [change-names...] ``` **Arguments:** | Argument | Required | Description | |----------|----------|-------------| | `change-names` | No | Specific changes to archive (prompts to select if not provided) | **What it does:** - Lists all completed changes - Validates each change before archiving - Detects spec conflicts across changes - Resolves conflicts by checking what's actually implemented - Archives in chronological order **Example:** ``` You: /opsx:bulk-archive AI: Found 3 completed changes: - add-dark-mode (8/8 tasks complete) - fix-login-bug (3/3 tasks complete) - update-footer (2/2 tasks complete) Checking for spec conflicts... ⚠ add-dark-mode and update-footer both touch specs/ui/ Inspecting codebase to resolve... Both changes are implemented. Will merge in chronological order: 1. add-dark-mode (created Jan 20) 2. update-footer (created Jan 22) Archive all 3 changes? You: Yes AI: ✓ Archived add-dark-mode ✓ Archived fix-login-bug ✓ Archived update-footer Specs merged: add-dark-mode → update-footer ``` **Tips:** - Good for parallel work streams - Conflict resolution is agentic (checks codebase) - Changes are archived in order of creation - Prompts before overwriting spec content --- ### `/opsx:onboard` Guided onboarding through the complete OpenSpec workflow. An interactive tutorial using your actual codebase. **Syntax:** ``` /opsx:onboard ``` **What it does:** - Walks through a complete workflow cycle with narration - Scans your codebase for real improvement opportunities - Creates an actual change with real artifacts - Implements actual work (small, safe changes) - Archives the completed change - Explains each step as it happens **Phases:** 1. Welcome and codebase analysis 2. Finding an improvement opportunity 3. Creating a change (`/opsx:new`) 4. Writing the proposal 5. Creating specs 6. Writing the design 7. Creating tasks 8. Implementing tasks (`/opsx:apply`) 9. Verifying implementation 10. Archiving the change 11. Summary and next steps **Example:** ``` You: /opsx:onboard AI: Welcome to OpenSpec! I'll walk you through the complete workflow using your actual codebase. We'll find something small to improve, create a proper change for it, implement it, and archive it. Let me scan your codebase for opportunities... [Analyzes codebase] I found a few things we could work on: 1. Add input validation to the contact form 2. Improve error messages in the auth flow 3. Add loading states to async buttons Which interests you? (or suggest something else) ``` **Tips:** - Best for new users learning the workflow - Uses real code, not toy examples - Creates a real change you can keep or discard - Takes 15-30 minutes to complete --- ## Command Syntax by AI Tool Different AI tools use slightly different command syntax. Use the format that matches your tool: | Tool | Syntax Example | |------|----------------| | Claude Code | `/opsx:propose`, `/opsx:apply` | | Cursor | `/opsx-propose`, `/opsx-apply` | | Windsurf | `/opsx-propose`, `/opsx-apply` | | Copilot (IDE) | `/opsx-propose`, `/opsx-apply` | | Trae | Skill-based invocations such as `/openspec-propose`, `/openspec-apply-change` (no generated `opsx-*` command files) | 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. --- ## Legacy Commands These commands use the older "all-at-once" workflow. They still work but OPSX commands are recommended. | Command | What it does | |---------|--------------| | `/openspec:proposal` | Create all artifacts at once (proposal, specs, design, tasks) | | `/openspec:apply` | Implement the change | | `/openspec:archive` | Archive the change | **When to use legacy commands:** - Existing projects using the old workflow - Simple changes where you don't need incremental artifact creation - Preference for the all-or-nothing approach **Migrating to OPSX:** Legacy changes can be continued with OPSX commands. The artifact structure is compatible. --- ## Troubleshooting ### "Change not found" The command couldn't identify which change to work on. **Solutions:** - Specify the change name explicitly: `/opsx:apply add-dark-mode` - Check that the change folder exists: `openspec list` - Verify you're in the right project directory ### "No artifacts ready" All artifacts are either complete or blocked by missing dependencies. **Solutions:** - Run `openspec status --change ` to see what's blocking - Check if required artifacts exist - Create missing dependency artifacts first ### "Schema not found" The specified schema doesn't exist. **Solutions:** - List available schemas: `openspec schemas` - Check spelling of schema name - Create the schema if it's custom: `openspec schema init ` ### Commands not recognized The AI tool doesn't recognize OpenSpec commands. **Solutions:** - Ensure OpenSpec is initialized: `openspec init` - Regenerate skills: `openspec update` - Check that `.claude/skills/` directory exists (for Claude Code) - Restart your AI tool to pick up new skills ### Artifacts not generating properly The AI creates incomplete or incorrect artifacts. **Solutions:** - Add project context in `openspec/config.yaml` - Add per-artifact rules for specific guidance - Provide more detail in your change description - Use `/opsx:continue` instead of `/opsx:ff` for more control --- ## Next Steps - [Workflows](workflows.md) - Common patterns and when to use each command - [CLI](cli.md) - Terminal commands for management and validation - [Customization](customization.md) - Create custom schemas and workflows ================================================ FILE: docs/concepts.md ================================================ # Concepts This guide explains the core ideas behind OpenSpec and how they fit together. For practical usage, see [Getting Started](getting-started.md) and [Workflows](workflows.md). ## Philosophy OpenSpec is built around four principles: ``` 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 ``` ### Why These Principles Matter **Fluid not rigid.** Traditional spec systems lock you into phases: first you plan, then you implement, then you're done. OpenSpec is more flexible — you can create artifacts in any order that makes sense for your work. **Iterative not waterfall.** Requirements change. Understanding deepens. What seemed like a good approach at the start might not hold up after you see the codebase. OpenSpec embraces this reality. **Easy not complex.** Some spec frameworks require extensive setup, rigid formats, or heavyweight processes. OpenSpec stays out of your way. Initialize in seconds, start working immediately, customize only if you need to. **Brownfield-first.** Most software work isn't building from scratch — it's modifying existing systems. OpenSpec's delta-based approach makes it easy to specify changes to existing behavior, not just describe new systems. ## The Big Picture 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 │ │ │ │ │ │ │ │ │ └─────────────────────┘ └──────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` **Specs** are the source of truth — they describe how your system currently behaves. **Changes** are proposed modifications — they live in separate folders until you're ready to merge them. This separation is key. You can work on multiple changes in parallel without conflicts. You can review a change before it affects the main specs. And when you archive a change, its deltas merge cleanly into the source of truth. ## Specs Specs describe your system's behavior using structured requirements and scenarios. ### Structure ``` openspec/specs/ ├── auth/ │ └── spec.md # Authentication behavior ├── payments/ │ └── spec.md # Payment processing ├── notifications/ │ └── spec.md # Notification system └── ui/ └── spec.md # UI behavior and themes ``` Organize specs by domain — logical groupings that make sense for your system. Common patterns: - **By feature area**: `auth/`, `payments/`, `search/` - **By component**: `api/`, `frontend/`, `workers/` - **By bounded context**: `ordering/`, `fulfillment/`, `inventory/` ### Spec Format A spec contains requirements, and each requirement has scenarios: ```markdown # Auth Specification ## Purpose Authentication and session management for the application. ## Requirements ### Requirement: User Authentication The system SHALL issue a JWT token upon successful login. #### Scenario: Valid credentials - GIVEN a user with valid credentials - WHEN the user submits login form - THEN a JWT token is returned - AND the user is redirected to dashboard #### Scenario: Invalid credentials - GIVEN invalid credentials - WHEN the user submits login form - THEN an error message is displayed - AND no token is issued ### Requirement: Session Expiration The system MUST expire sessions after 30 minutes of inactivity. #### Scenario: Idle timeout - GIVEN an authenticated session - WHEN 30 minutes pass without activity - THEN the session is invalidated - AND the user must re-authenticate ``` **Key elements:** | Element | Purpose | |---------|---------| | `## Purpose` | High-level description of this spec's domain | | `### Requirement:` | A specific behavior the system must have | | `#### Scenario:` | A concrete example of the requirement in action | | SHALL/MUST/SHOULD | RFC 2119 keywords indicating requirement strength | ### Why Structure Specs This Way **Requirements are the "what"** — they state what the system should do without specifying implementation. **Scenarios are the "when"** — they provide concrete examples that can be verified. Good scenarios: - Are testable (you could write an automated test for them) - Cover both happy path and edge cases - Use Given/When/Then or similar structured format **RFC 2119 keywords** (SHALL, MUST, SHOULD, MAY) communicate intent: - **MUST/SHALL** — absolute requirement - **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. ### Change Structure ``` openspec/changes/add-dark-mode/ ├── proposal.md # Why and what ├── design.md # How (technical approach) ├── tasks.md # Implementation checklist ├── .openspec.yaml # Change metadata (optional) └── specs/ # Delta specs └── ui/ └── spec.md # What's changing in ui/spec.md ``` Each change is self-contained. It has: - **Artifacts** — documents that capture intent, design, and tasks - **Delta specs** — specifications for what's being added, modified, or removed - **Metadata** — optional configuration for this specific change ### Why Changes Are Folders Packaging a change as a folder has several benefits: 1. **Everything together.** Proposal, design, tasks, and specs live in one place. No hunting through different locations. 2. **Parallel work.** Multiple changes can exist simultaneously without conflicting. Work on `add-dark-mode` while `fix-auth-bug` is also in progress. 3. **Clean history.** When archived, changes move to `changes/archive/` with their full context preserved. You can look back and understand not just what changed, but why. 4. **Review-friendly.** A change folder is easy to review — open it, read the proposal, check the design, see the spec deltas. ## Artifacts Artifacts are the documents within a change that guide the work. ### The Artifact Flow ``` proposal ──────► specs ──────► design ──────► tasks ──────► implement │ │ │ │ why what how steps + scope changes approach to take ``` Artifacts build on each other. Each artifact provides context for the next. ### Artifact Types #### Proposal (`proposal.md`) The proposal captures **intent**, **scope**, and **approach** at a high level. ```markdown # Proposal: Add Dark Mode ## Intent Users have requested a dark mode option to reduce eye strain during nighttime usage and match system preferences. ## Scope In scope: - Theme toggle in settings - System preference detection - Persist preference in localStorage Out of scope: - Custom color themes (future work) - Per-page theme overrides ## Approach Use CSS custom properties for theming with a React context for state management. Detect system preference on first load, allow manual override. ``` **When to update the proposal:** - Scope changes (narrowing or expanding) - Intent clarifies (better understanding of the problem) - Approach fundamentally shifts #### Specs (delta specs in `specs/`) Delta specs describe **what's changing** relative to the current specs. See [Delta Specs](#delta-specs) below. #### Design (`design.md`) The design captures **technical approach** and **architecture decisions**. ````markdown # Design: Add Dark Mode ## Technical Approach Theme state managed via React Context to avoid prop drilling. CSS custom properties enable runtime switching without class toggling. ## Architecture Decisions ### Decision: Context over Redux Using React Context for theme state because: - Simple binary state (light/dark) - No complex state transitions - Avoids adding Redux dependency ### Decision: CSS Custom Properties Using CSS variables instead of CSS-in-JS because: - Works with existing stylesheet - No runtime overhead - Browser-native solution ## Data Flow ``` ThemeProvider (context) │ ▼ ThemeToggle ◄──► localStorage │ ▼ CSS Variables (applied to :root) ``` ## File Changes - `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 - Better solution discovered - Dependencies or constraints change #### Tasks (`tasks.md`) Tasks are the **implementation checklist** — concrete steps with checkboxes. ```markdown # Tasks ## 1. Theme Infrastructure - [ ] 1.1 Create ThemeContext with light/dark state - [ ] 1.2 Add CSS custom properties for colors - [ ] 1.3 Implement localStorage persistence - [ ] 1.4 Add system preference detection ## 2. UI Components - [ ] 2.1 Create ThemeToggle component - [ ] 2.2 Add toggle to settings page - [ ] 2.3 Update Header to include quick toggle ## 3. Styling - [ ] 3.1 Define dark theme color palette - [ ] 3.2 Update components to use CSS variables - [ ] 3.3 Test contrast ratios for accessibility ``` **Task best practices:** - Group related tasks under headings - Use hierarchical numbering (1.1, 1.2, etc.) - Keep tasks small enough to complete in one session - Check tasks off as you complete them ## Delta Specs Delta specs are the key concept that makes OpenSpec work for brownfield development. They describe **what's changing** rather than restating the entire spec. ### The Format ```markdown # Delta for Auth ## ADDED Requirements ### Requirement: Two-Factor Authentication The system MUST support TOTP-based two-factor authentication. #### Scenario: 2FA enrollment - GIVEN a user without 2FA enabled - WHEN the user enables 2FA in settings - THEN a QR code is displayed for authenticator app setup - AND the user must verify with a code before activation #### Scenario: 2FA login - GIVEN a user with 2FA enabled - WHEN the user submits valid credentials - THEN an OTP challenge is presented - AND login completes only after valid OTP ## MODIFIED Requirements ### Requirement: Session Expiration The system MUST expire sessions after 15 minutes of inactivity. (Previously: 30 minutes) #### Scenario: Idle timeout - GIVEN an authenticated session - WHEN 15 minutes pass without activity - THEN the session is invalidated ## REMOVED Requirements ### Requirement: Remember Me (Deprecated in favor of 2FA. Users should re-authenticate each session.) ``` ### Delta Sections | Section | Meaning | What Happens on Archive | |---------|---------|------------------------| | `## ADDED Requirements` | New behavior | Appended to main spec | | `## MODIFIED Requirements` | Changed behavior | Replaces existing requirement | | `## REMOVED Requirements` | Deprecated behavior | Deleted from main spec | ### Why Deltas Instead of Full Specs **Clarity.** A delta shows exactly what's changing. Reading a full spec, you'd have to diff it mentally against the current version. **Conflict avoidance.** Two changes can touch the same spec file without conflicting, as long as they modify different requirements. **Review efficiency.** Reviewers see the change, not the unchanged context. Focus on what matters. **Brownfield fit.** Most work modifies existing behavior. Deltas make modifications first-class, not an afterthought. ## Schemas Schemas define the artifact types and their dependencies for a workflow. ### How Schemas Work ```yaml # openspec/schemas/spec-driven/schema.yaml name: spec-driven artifacts: - id: proposal generates: proposal.md requires: [] # No dependencies, can create first - id: specs generates: specs/**/*.md requires: [proposal] # Needs proposal before creating - id: design generates: design.md requires: [proposal] # Can create in parallel with specs - id: tasks generates: tasks.md requires: [specs, design] # Needs both specs and design first ``` **Artifacts form a dependency graph:** ``` proposal (root node) │ ┌─────────────┴─────────────┐ │ │ ▼ ▼ specs design (requires: (requires: proposal) proposal) │ │ └─────────────┬─────────────┘ │ ▼ tasks (requires: specs, design) ``` **Dependencies are enablers, not gates.** They show what's possible to create, not what you must create next. You can skip design if you don't need it. You can create specs before or after design — both depend only on proposal. ### Built-in Schemas **spec-driven** (default) The standard workflow for spec-driven development: ``` proposal → specs → design → tasks → implement ``` Best for: Most feature work where you want to agree on specs before implementation. ### Custom Schemas Create custom schemas for your team's workflow: ```bash # Create from scratch openspec schema init research-first # Or fork an existing one openspec schema fork spec-driven research-first ``` **Example custom schema:** ```yaml # openspec/schemas/research-first/schema.yaml name: research-first artifacts: - id: research generates: research.md requires: [] # Do research first - id: proposal generates: proposal.md requires: [research] # Proposal informed by research - id: tasks generates: tasks.md requires: [proposal] # Skip specs/design, go straight to tasks ``` See [Customization](customization.md) for full details on creating and using custom schemas. ## Archive Archiving completes a change by merging its delta specs into the main specs and preserving the change for history. ### What Happens When You Archive ``` Before archive: openspec/ ├── specs/ │ └── auth/ │ └── spec.md ◄────────────────┐ └── changes/ │ └── add-2fa/ │ ├── proposal.md │ ├── design.md │ merge ├── tasks.md │ └── specs/ │ └── auth/ │ └── spec.md ─────────┘ After archive: openspec/ ├── specs/ │ └── auth/ │ └── spec.md # Now includes 2FA requirements └── changes/ └── archive/ └── 2025-01-24-add-2fa/ # Preserved for history ├── proposal.md ├── design.md ├── tasks.md └── specs/ └── auth/ └── spec.md ``` ### The Archive Process 1. **Merge deltas.** Each delta spec section (ADDED/MODIFIED/REMOVED) is applied to the corresponding main spec. 2. **Move to archive.** The change folder moves to `changes/archive/` with a date prefix for chronological ordering. 3. **Preserve context.** All artifacts remain intact in the archive. You can always look back to understand why a change was made. ### Why Archive Matters **Clean state.** Active changes (`changes/`) shows only work in progress. Completed work moves out of the way. **Audit trail.** The archive preserves the full context of every change — not just what changed, but the proposal explaining why, the design explaining how, and the tasks showing the work done. **Spec evolution.** Specs grow organically as changes are archived. Each archive merges its deltas, building up a comprehensive specification over time. ## How It All Fits Together ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ OPENSPEC FLOW │ │ │ │ ┌────────────────┐ │ │ │ 1. START │ /opsx:propose (core) or /opsx:new (expanded) │ │ │ CHANGE │ │ │ └───────┬────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────┐ │ │ │ 2. CREATE │ /opsx:ff or /opsx:continue (expanded workflow) │ │ │ ARTIFACTS │ Creates proposal → specs → design → tasks │ │ │ │ (based on schema dependencies) │ │ └───────┬────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────┐ │ │ │ 3. IMPLEMENT │ /opsx:apply │ │ │ TASKS │ Work through tasks, checking them off │ │ │ │◄──── Update artifacts as you learn │ │ └───────┬────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────┐ │ │ │ 4. VERIFY │ /opsx:verify (optional) │ │ │ WORK │ Check implementation matches specs │ │ └───────┬────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────┐ ┌──────────────────────────────────────────────┐ │ │ │ 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:** 1. Specs describe current behavior 2. Changes propose modifications (as deltas) 3. Implementation makes the changes real 4. Archive merges deltas into specs 5. Specs now describe the new behavior 6. Next change builds on updated specs ## Glossary | Term | Definition | |------|------------| | **Artifact** | A document within a change (proposal, design, tasks, or delta specs) | | **Archive** | The process of completing a change and merging its deltas into main specs | | **Change** | A proposed modification to the system, packaged as a folder with artifacts | | **Delta spec** | A spec that describes changes (ADDED/MODIFIED/REMOVED) relative to current specs | | **Domain** | A logical grouping for specs (e.g., `auth/`, `payments/`) | | **Requirement** | A specific behavior the system must have | | **Scenario** | A concrete example of a requirement, typically in Given/When/Then format | | **Schema** | A definition of artifact types and their dependencies | | **Spec** | A specification describing system behavior, containing requirements and scenarios | | **Source of truth** | The `openspec/specs/` directory, containing the current agreed-upon behavior | ## Next Steps - [Getting Started](getting-started.md) - Practical first steps - [Workflows](workflows.md) - Common patterns and when to use each - [Commands](commands.md) - Full command reference - [Customization](customization.md) - Create custom schemas and configure your project ================================================ FILE: docs/customization.md ================================================ # Customization OpenSpec provides three levels of customization: | Level | What it does | Best for | |-------|--------------|----------| | **Project Config** | Set defaults, inject context/rules | Most teams | | **Custom Schemas** | Define your own workflow artifacts | Teams with unique processes | | **Global Overrides** | Share schemas across all projects | Power users | --- ## Project Configuration The `openspec/config.yaml` file is the easiest way to customize OpenSpec for your team. It lets you: - **Set a default schema** - Skip `--schema` on every command - **Inject project context** - AI sees your tech stack, conventions, etc. - **Add per-artifact rules** - Custom rules for specific artifacts ### Quick Setup ```bash openspec init ``` This walks you through creating a config interactively. Or create one manually: ```yaml # openspec/config.yaml schema: spec-driven context: | Tech stack: TypeScript, React, Node.js, PostgreSQL API style: RESTful, documented in docs/api.md Testing: Jest + React Testing Library We value backwards compatibility for all public APIs rules: proposal: - Include rollback plan - Identify affected teams specs: - Use Given/When/Then format - Reference existing patterns before inventing new ones ``` ### How It Works **Default schema:** ```bash # Without config openspec new change my-feature --schema spec-driven # With config - schema is automatic openspec new change my-feature ``` **Context and rules injection:** When generating any artifact, your context and rules are injected into the AI prompt: ```xml Tech stack: TypeScript, React, Node.js, PostgreSQL ... - Include rollback plan - Identify affected teams ``` - **Context** appears in ALL artifacts - **Rules** ONLY appear for the matching artifact ### Schema Resolution Order When OpenSpec needs a schema, it checks in this order: 1. CLI flag: `--schema ` 2. Change metadata (`.openspec.yaml` in the change folder) 3. Project config (`openspec/config.yaml`) 4. Default (`spec-driven`) --- ## Custom Schemas When project config isn't enough, create your own schema with a completely custom workflow. Custom schemas live in your project's `openspec/schemas/` directory and are version-controlled with your code. ```text your-project/ ├── openspec/ │ ├── config.yaml # Project config │ ├── schemas/ # Custom schemas live here │ │ └── my-workflow/ │ │ ├── schema.yaml │ │ └── templates/ │ └── changes/ # Your changes └── src/ ``` ### Fork an Existing Schema The fastest way to customize is to fork a built-in schema: ```bash openspec schema fork spec-driven my-workflow ``` This copies the entire `spec-driven` schema to `openspec/schemas/my-workflow/` where you can edit it freely. **What you get:** ```text openspec/schemas/my-workflow/ ├── schema.yaml # Workflow definition └── templates/ ├── proposal.md # Template for proposal artifact ├── spec.md # Template for specs ├── design.md # Template for design └── tasks.md # Template for tasks ``` Now edit `schema.yaml` to change the workflow, or edit templates to change what AI generates. ### Create a Schema from Scratch For a completely fresh workflow: ```bash # Interactive openspec schema init research-first # Non-interactive openspec schema init rapid \ --description "Rapid iteration workflow" \ --artifacts "proposal,tasks" \ --default ``` ### Schema Structure A schema defines the artifacts in your workflow and how they depend on each other: ```yaml # openspec/schemas/my-workflow/schema.yaml name: my-workflow version: 1 description: My team's custom workflow artifacts: - id: proposal generates: proposal.md description: Initial proposal document template: proposal.md instruction: | Create a proposal that explains WHY this change is needed. Focus on the problem, not the solution. requires: [] - id: design generates: design.md description: Technical design template: design.md instruction: | Create a design document explaining HOW to implement. requires: - proposal # Can't create design until proposal exists - id: tasks generates: tasks.md description: Implementation checklist template: tasks.md requires: - design apply: requires: [tasks] tracks: tasks.md ``` **Key fields:** | Field | Purpose | |-------|---------| | `id` | Unique identifier, used in commands and rules | | `generates` | Output filename (supports globs like `specs/**/*.md`) | | `template` | Template file in `templates/` directory | | `instruction` | AI instructions for creating this artifact | | `requires` | Dependencies - which artifacts must exist first | ### Templates Templates are markdown files that guide the AI. They're injected into the prompt when creating that artifact. ```markdown ## Why ## What Changes ## Impact ``` Templates can include: - Section headers the AI should fill in - HTML comments with guidance for the AI - Example formats showing expected structure ### Validate Your Schema Before using a custom schema, validate it: ```bash openspec schema validate my-workflow ``` This checks: - `schema.yaml` syntax is correct - All referenced templates exist - No circular dependencies - Artifact IDs are valid ### Use Your Custom Schema Once created, use your schema with: ```bash # Specify on command openspec new change feature --schema my-workflow # Or set as default in config.yaml schema: my-workflow ``` ### Debug Schema Resolution Not sure which schema is being used? Check with: ```bash # See where a specific schema resolves from openspec schema which my-workflow # List all available schemas openspec schema which --all ``` Output shows whether it's from your project, user directory, or the package: ```text Schema: my-workflow Source: project Path: /path/to/project/openspec/schemas/my-workflow ``` --- > **Note:** OpenSpec also supports user-level schemas at `~/.local/share/openspec/schemas/` for sharing across projects, but project-level schemas in `openspec/schemas/` are recommended since they're version-controlled with your code. --- ## Examples ### Rapid Iteration Workflow A minimal workflow for quick iterations: ```yaml # openspec/schemas/rapid/schema.yaml name: rapid version: 1 description: Fast iteration with minimal overhead artifacts: - id: proposal generates: proposal.md description: Quick proposal template: proposal.md instruction: | Create a brief proposal for this change. Focus on what and why, skip detailed specs. requires: [] - id: tasks generates: tasks.md description: Implementation checklist template: tasks.md requires: [proposal] apply: requires: [tasks] tracks: tasks.md ``` ### Adding a Review Artifact Fork the default and add a review step: ```bash openspec schema fork spec-driven with-review ``` Then edit `schema.yaml` to add: ```yaml - id: review generates: review.md description: Pre-implementation review checklist template: review.md instruction: | Create a review checklist based on the design. Include security, performance, and testing considerations. requires: - design - id: tasks # ... existing tasks config ... requires: - specs - design - review # Now tasks require review too ``` --- ## See Also - [CLI Reference: Schema Commands](cli.md#schema-commands) - Full command documentation ================================================ FILE: docs/getting-started.md ================================================ # Getting Started This guide explains how OpenSpec works after you've installed and initialized it. For installation instructions, see the [main README](../README.md#quick-start). ## How It Works 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 ``` **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: ``` openspec/ ├── specs/ # Source of truth (your system's behavior) │ └── / │ └── spec.md ├── changes/ # Proposed updates (one folder per change) │ └── / │ ├── proposal.md │ ├── design.md │ ├── tasks.md │ └── specs/ # Delta specs (what's changing) │ └── / │ └── spec.md └── config.yaml # Project configuration (optional) ``` **Two key directories:** - **`specs/`** - The source of truth. These specs describe how your system currently behaves. Organized by domain (e.g., `specs/auth/`, `specs/payments/`). - **`changes/`** - Proposed modifications. Each change gets its own folder with all related artifacts. When a change is complete, its specs merge into the main `specs/` directory. ## Understanding Artifacts Each change folder contains artifacts that guide the work: | Artifact | Purpose | |----------|---------| | `proposal.md` | The "why" and "what" - captures intent, scope, and approach | | `specs/` | Delta specs showing ADDED/MODIFIED/REMOVED requirements | | `design.md` | The "how" - technical approach and architecture decisions | | `tasks.md` | Implementation checklist with checkboxes | **Artifacts build on each other:** ``` proposal ──► specs ──► design ──► tasks ──► implement ▲ ▲ ▲ │ └───────────┴──────────┴────────────────────┘ update as you learn ``` You can always go back and refine earlier artifacts as you learn more during implementation. ## How Delta Specs Work Delta specs are the key concept in OpenSpec. They show what's changing relative to your current specs. ### The Format Delta specs use sections to indicate the type of change: ```markdown # Delta for Auth ## ADDED Requirements ### Requirement: Two-Factor Authentication The system MUST require a second factor during login. #### Scenario: OTP required - GIVEN a user with 2FA enabled - WHEN the user submits valid credentials - THEN an OTP challenge is presented ## MODIFIED Requirements ### Requirement: Session Timeout The system SHALL expire sessions after 30 minutes of inactivity. (Previously: 60 minutes) #### Scenario: Idle timeout - GIVEN an authenticated session - WHEN 30 minutes pass without activity - THEN the session is invalidated ## REMOVED Requirements ### Requirement: Remember Me (Deprecated in favor of 2FA) ``` ### What Happens on Archive When you archive a change: 1. **ADDED** requirements are appended to the main spec 2. **MODIFIED** requirements replace the existing version 3. **REMOVED** requirements are deleted from the main spec The change folder moves to `openspec/changes/archive/` for audit history. ## Example: Your First Change Let's walk through adding dark mode to an application. ### 1. Start the Change (Default) ```text You: /opsx:propose add-dark-mode AI: Created openspec/changes/add-dark-mode/ ✓ proposal.md — why we're doing this, what's changing ✓ specs/ — requirements and scenarios ✓ design.md — technical approach ✓ tasks.md — implementation checklist Ready for implementation! ``` If you've enabled the expanded workflow profile, you can also do this as two steps: `/opsx:new` then `/opsx:ff` (or `/opsx:continue` incrementally). ### 2. What Gets Created **proposal.md** - Captures the intent: ```markdown # Proposal: Add Dark Mode ## Intent Users have requested a dark mode option to reduce eye strain during nighttime usage. ## Scope - Add theme toggle in settings - Support system preference detection - Persist preference in localStorage ## Approach Use CSS custom properties for theming with a React context for state management. ``` **specs/ui/spec.md** - Delta showing new requirements: ```markdown # Delta for UI ## ADDED Requirements ### Requirement: Theme Selection The system SHALL allow users to choose between light and dark themes. #### Scenario: Manual toggle - GIVEN a user on any page - WHEN the user clicks the theme toggle - THEN the theme switches immediately - AND the preference persists across sessions #### Scenario: System preference - GIVEN a user with no saved preference - WHEN the application loads - THEN the system's preferred color scheme is used ``` **tasks.md** - Implementation checklist: ```markdown # Tasks ## 1. Theme Infrastructure - [ ] 1.1 Create ThemeContext with light/dark state - [ ] 1.2 Add CSS custom properties for colors - [ ] 1.3 Implement localStorage persistence ## 2. UI Components - [ ] 2.1 Create ThemeToggle component - [ ] 2.2 Add toggle to settings page - [ ] 2.3 Update Header to include quick toggle ## 3. Styling - [ ] 3.1 Define dark theme color palette - [ ] 3.2 Update components to use CSS variables ``` ### 3. Implement ``` You: /opsx:apply AI: Working through tasks... ✓ 1.1 Created ThemeContext with light/dark state ✓ 1.2 Added CSS custom properties to globals.css ✓ 1.3 Implemented localStorage persistence ✓ 2.1 Created ThemeToggle component ... All tasks complete! ``` During implementation, if you discover the design needs adjustment, just update the artifact and continue. ### 4. Archive ``` You: /opsx:archive AI: Archiving add-dark-mode... ✓ Merged specs into openspec/specs/ui/spec.md ✓ Moved to openspec/changes/archive/2025-01-24-add-dark-mode/ Done! Ready for the next feature. ``` Your delta specs are now part of the main specs, documenting how your system works. ## Verifying and Reviewing Use the CLI to check on your changes: ```bash # List active changes openspec list # View change details openspec show add-dark-mode # Validate spec formatting openspec validate add-dark-mode # Interactive dashboard openspec view ``` ## Next Steps - [Workflows](workflows.md) - Common patterns and when to use each command - [Commands](commands.md) - Full reference for all slash commands - [Concepts](concepts.md) - Deeper understanding of specs, changes, and schemas - [Customization](customization.md) - Make OpenSpec work your way ================================================ FILE: docs/installation.md ================================================ # Installation ## Prerequisites - **Node.js 20.19.0 or higher** — Check your version: `node --version` ## Package Managers ### npm ```bash npm install -g @fission-ai/openspec@latest ``` ### pnpm ```bash pnpm add -g @fission-ai/openspec@latest ``` ### yarn ```bash yarn global add @fission-ai/openspec@latest ``` ### bun ```bash bun add -g @fission-ai/openspec@latest ``` ## Nix Run OpenSpec directly without installation: ```bash nix run github:Fission-AI/OpenSpec -- init ``` Or install to your profile: ```bash nix profile install github:Fission-AI/OpenSpec ``` Or add to your development environment in `flake.nix`: ```nix { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; openspec.url = "github:Fission-AI/OpenSpec"; }; outputs = { nixpkgs, openspec, ... }: { devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell { buildInputs = [ openspec.packages.x86_64-linux.default ]; }; }; } ``` ## Verify Installation ```bash openspec --version ``` ## Next Steps After installing, initialize OpenSpec in your project: ```bash cd your-project openspec init ``` See [Getting Started](getting-started.md) for a full walkthrough. ================================================ FILE: docs/migration-guide.md ================================================ # Migrating to OPSX This guide helps you transition from the legacy OpenSpec workflow to OPSX. The migration is designed to be smooth—your existing work is preserved, and the new system offers more flexibility. ## What's Changing? OPSX replaces the old phase-locked workflow with a fluid, action-based approach. Here's the key shift: | Aspect | Legacy | OPSX | |--------|--------|------| | **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 | | **Configuration** | `CLAUDE.md` with markers + `project.md` | Clean config in `openspec/config.yaml` | **The philosophy change:** Work isn't linear. OPSX stops pretending it is. --- ## Before You Begin ### Your Existing Work Is Safe The migration process is designed with preservation in mind: - **Active changes in `openspec/changes/`** — Completely preserved. You can continue them with OPSX commands. - **Archived changes** — Untouched. Your history remains intact. - **Main specs in `openspec/specs/`** — Untouched. These are your source of truth. - **Your content in CLAUDE.md, AGENTS.md, etc.** — Preserved. Only the OpenSpec marker blocks are removed; everything you wrote stays. ### What Gets Removed Only OpenSpec-managed files that are being replaced: | What | Why | |------|-----| | Legacy slash command directories/files | Replaced by the new skills system | | `openspec/AGENTS.md` | Obsolete workflow trigger | | OpenSpec markers in `CLAUDE.md`, `AGENTS.md`, etc. | No longer needed | **Legacy command locations by tool** (examples—your tool may vary): - Claude Code: `.claude/commands/openspec/` - Cursor: `.cursor/commands/openspec-*.md` - Windsurf: `.windsurf/workflows/openspec-*.md` - Cline: `.clinerules/workflows/openspec-*.md` - Roo: `.roo/commands/openspec-*.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. The removal list may seem long, but these are all files that OpenSpec originally created. Your own content is never deleted. ### What Needs Your Attention One file requires manual migration: **`openspec/project.md`** — This file isn't deleted automatically because it may contain project context you've written. You'll need to: 1. Review its contents 2. Move useful context to `openspec/config.yaml` (see guidance below) 3. Delete the file when ready **Why we made this change:** The old `project.md` was passive—agents might read it, might not, might forget what they read. We found reliability was inconsistent. The new `config.yaml` context is **actively injected into every OpenSpec planning request**. This means your project conventions, tech stack, and rules are always present when the AI is creating artifacts. Higher reliability. **The tradeoff:** Because context is injected into every request, you'll want to be concise. Focus on what really matters: - Tech stack and key conventions - Non-obvious constraints the AI needs to know - Rules that frequently got ignored before Don't worry about getting it perfect. We're still learning what works best here, and we'll be improving how context injection works as we experiment. --- ## Running the Migration 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: ```bash openspec init ``` The init command detects legacy files and guides you through cleanup: ``` Upgrading to the new OpenSpec OpenSpec now uses agent skills, the emerging standard across coding agents. This simplifies your setup while keeping everything working as before. Files to remove No user content to preserve: • .claude/commands/openspec/ • openspec/AGENTS.md Files to update OpenSpec markers will be removed, your content preserved: • CLAUDE.md • AGENTS.md Needs your attention • openspec/project.md We won't delete this file. It may contain useful project context. The new openspec/config.yaml has a "context:" section for planning context. This is included in every OpenSpec request and works more reliably than the old project.md approach. Review project.md, move any useful content to config.yaml's context section, then delete the file when ready. ? Upgrade and clean up legacy files? (Y/n) ``` **What happens when you say yes:** 1. Legacy slash command directories are removed 2. OpenSpec markers are stripped from `CLAUDE.md`, `AGENTS.md`, etc. (your content stays) 3. `openspec/AGENTS.md` is deleted 4. New skills are installed in `.claude/skills/` 5. `openspec/config.yaml` is created with a default schema ### Using `openspec update` Run this if you just want to migrate and refresh your existing tools to the latest version: ```bash openspec update ``` 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 For scripted migrations: ```bash openspec init --force --tools claude ``` The `--force` flag skips prompts and auto-accepts cleanup. --- ## Migrating project.md to config.yaml The old `openspec/project.md` was a freeform markdown file for project context. The new `openspec/config.yaml` is structured and—critically—**injected into every planning request** so your conventions are always present when the AI works. ### Before (project.md) ```markdown # Project Context This is a TypeScript monorepo using React and Node.js. We use Jest for testing and follow strict ESLint rules. Our API is RESTful and documented in docs/api.md. ## Conventions - All public APIs must maintain backwards compatibility - New features should include tests - Use Given/When/Then format for specifications ``` ### After (config.yaml) ```yaml schema: spec-driven context: | Tech stack: TypeScript, React, Node.js Testing: Jest with React Testing Library API: RESTful, documented in docs/api.md We maintain backwards compatibility for all public APIs rules: proposal: - Include rollback plan for risky changes specs: - Use Given/When/Then format for scenarios - Reference existing patterns before inventing new ones design: - Include sequence diagrams for complex flows ``` ### Key Differences | project.md | config.yaml | |------------|-------------| | Freeform markdown | Structured YAML | | One blob of text | Separate context and per-artifact rules | | Unclear when it's used | Context appears in ALL artifacts; rules appear in matching artifacts only | | No schema selection | Explicit `schema:` field sets default workflow | ### What to Keep, What to Drop When migrating, be selective. Ask yourself: "Does the AI need this for *every* planning request?" **Good candidates for `context:`** - Tech stack (languages, frameworks, databases) - Key architectural patterns (monorepo, microservices, etc.) - Non-obvious constraints ("we can't use library X because...") - Critical conventions that often get ignored **Move to `rules:` instead** - Artifact-specific formatting ("use Given/When/Then in specs") - Review criteria ("proposals must include rollback plans") - These only appear for the matching artifact, keeping other requests lighter **Leave out entirely** - General best practices the AI already knows - Verbose explanations that could be summarized - Historical context that doesn't affect current work ### Migration Steps 1. **Create config.yaml** (if not already created by init): ```yaml schema: spec-driven ``` 2. **Add your context** (be concise—this goes into every request): ```yaml context: | Your project background goes here. Focus on what the AI genuinely needs to know. ``` 3. **Add per-artifact rules** (optional): ```yaml rules: proposal: - Your proposal-specific guidance specs: - Your spec-writing rules ``` 4. **Delete project.md** once you've moved everything useful. **Don't overthink it.** Start with the essentials and iterate. If you notice the AI missing something important, add it. If context feels bloated, trim it. This is a living document. ### Need Help? Use This Prompt If you're unsure how to distill your project.md, ask your AI assistant: ``` I'm migrating from OpenSpec's old project.md to the new config.yaml format. Here's my current project.md: [paste your project.md content] Please help me create a config.yaml with: 1. A concise `context:` section (this gets injected into every planning request, so keep it tight—focus on tech stack, key constraints, and conventions that often get ignored) 2. `rules:` for specific artifacts if any content is artifact-specific (e.g., "use Given/When/Then" belongs in specs rules, not global context) Leave out anything generic that AI models already know. Be ruthless about brevity. ``` The AI will help you identify what's essential vs. what can be trimmed. --- ## The New Commands 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:apply` | Implement tasks from tasks.md | | `/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: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 ``` Creates one artifact at a time based on dependencies. Use this when you want to review each step. **Exploration mode:** ``` /opsx:explore ``` Think through ideas with a partner before committing to a change. --- ## Understanding the New Architecture ### From Phase-Locked to Fluid The legacy workflow forced linear progression: ``` ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ PLANNING │ ───► │ IMPLEMENTING │ ───► │ ARCHIVING │ │ PHASE │ │ PHASE │ │ PHASE │ └──────────────┘ └──────────────┘ └──────────────┘ If you're in implementation and realize the design is wrong? Too bad. Phase gates don't let you go back easily. ``` OPSX uses actions, not phases: ``` ┌───────────────────────────────────────────────┐ │ ACTIONS (not phases) │ │ │ │ new ◄──► continue ◄──► apply ◄──► archive │ │ │ │ │ │ │ │ └──────────┴───────────┴─────────────┘ │ │ any order │ └───────────────────────────────────────────────┘ ``` ### Dependency Graph Artifacts form a directed graph. Dependencies are enablers, not gates: ``` proposal (root node) │ ┌─────────────┴─────────────┐ │ │ ▼ ▼ specs design (requires: (requires: proposal) proposal) │ │ └─────────────┬─────────────┘ │ ▼ tasks (requires: specs, design) ``` When you run `/opsx:continue`, it checks what's ready and offers the next artifact. You can also create multiple ready artifacts in any order. ### Skills vs Commands The legacy system used tool-specific command files: ``` .claude/commands/openspec/ ├── proposal.md ├── apply.md └── archive.md ``` OPSX uses the emerging **skills** standard: ``` .claude/skills/ ├── openspec-explore/SKILL.md ├── openspec-new-change/SKILL.md ├── openspec-continue-change/SKILL.md ├── openspec-apply-change/SKILL.md └── ... ``` Skills are recognized across multiple AI coding tools and provide richer metadata. --- ## Continuing Existing Changes Your in-progress changes work seamlessly with OPSX commands. **Have an active change from the legacy workflow?** ``` /opsx:apply add-my-feature ``` OPSX reads the existing artifacts and continues from where you left off. **Want to add more artifacts to an existing change?** ``` /opsx:continue add-my-feature ``` Shows what's ready to create based on what already exists. **Need to see status?** ```bash openspec status --change add-my-feature ``` --- ## The New Config System ### config.yaml Structure ```yaml # Required: Default schema for new changes schema: spec-driven # Optional: Project context (max 50KB) # Injected into ALL artifact instructions context: | Your project background, tech stack, conventions, and constraints. # Optional: Per-artifact rules # Only injected into matching artifacts rules: proposal: - Include rollback plan specs: - Use Given/When/Then format design: - Document fallback strategies tasks: - Break into 2-hour maximum chunks ``` ### Schema Resolution When determining which schema to use, OPSX checks in order: 1. **CLI flag**: `--schema ` (highest priority) 2. **Change metadata**: `.openspec.yaml` in the change directory 3. **Project config**: `openspec/config.yaml` 4. **Default**: `spec-driven` ### Available Schemas | Schema | Artifacts | Best For | |--------|-----------|----------| | `spec-driven` | proposal → specs → design → tasks | Most projects | List all available schemas: ```bash openspec schemas ``` ### Custom Schemas Create your own workflow: ```bash openspec schema init my-workflow ``` Or fork an existing one: ```bash openspec schema fork spec-driven my-workflow ``` See [Customization](customization.md) for details. --- ## Troubleshooting ### "Legacy files detected in non-interactive mode" You're running in a CI or non-interactive environment. Use: ```bash openspec init --force ``` ### Commands not appearing after migration Restart your IDE. Skills are detected at startup. ### "Unknown artifact ID in rules" Check that your `rules:` keys match your schema's artifact IDs: - **spec-driven**: `proposal`, `specs`, `design`, `tasks` Run this to see valid artifact IDs: ```bash openspec schemas --json ``` ### Config not being applied 1. Ensure the file is at `openspec/config.yaml` (not `.yml`) 2. Validate YAML syntax 3. Config changes take effect immediately—no restart needed ### project.md not migrated The system intentionally preserves `project.md` because it may contain your custom content. Review it manually, move useful parts to `config.yaml`, then delete it. ### Want to see what would be cleaned up? Run init and decline the cleanup prompt—you'll see the full detection summary without any changes being made. --- ## Quick Reference ### Files After Migration ``` project/ ├── openspec/ │ ├── specs/ # Unchanged │ ├── changes/ # Unchanged │ │ └── archive/ # Unchanged │ └── config.yaml # NEW: Project configuration ├── .claude/ │ └── skills/ # NEW: OPSX skills │ ├── openspec-propose/ # default core profile │ ├── openspec-explore/ │ ├── 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 ``` ### What's Gone - `.claude/commands/openspec/` — replaced by `.claude/skills/` - `openspec/AGENTS.md` — obsolete - `openspec/project.md` — migrate to `config.yaml`, then delete - OpenSpec marker blocks in `CLAUDE.md`, `AGENTS.md`, etc. ### Command Cheatsheet ```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 ``` --- ## Getting Help - **Discord**: [discord.gg/YctCnvvshC](https://discord.gg/YctCnvvshC) - **GitHub Issues**: [github.com/Fission-AI/OpenSpec/issues](https://github.com/Fission-AI/OpenSpec/issues) - **Documentation**: [docs/opsx.md](opsx.md) for the full OPSX reference ================================================ FILE: docs/multi-language.md ================================================ # Multi-Language Guide Configure OpenSpec to generate artifacts in languages other than English. ## Quick Setup Add a language instruction to your `openspec/config.yaml`: ```yaml schema: spec-driven context: | Language: Portuguese (pt-BR) All artifacts must be written in Brazilian Portuguese. # Your other project context below... Tech stack: TypeScript, React, Node.js ``` That's it. All generated artifacts will now be in Portuguese. ## Language Examples ### Portuguese (Brazil) ```yaml context: | Language: Portuguese (pt-BR) All artifacts must be written in Brazilian Portuguese. ``` ### Spanish ```yaml context: | Idioma: Español Todos los artefactos deben escribirse en español. ``` ### Chinese (Simplified) ```yaml context: | 语言:中文(简体) 所有产出物必须用简体中文撰写。 ``` ### Japanese ```yaml context: | 言語:日本語 すべての成果物は日本語で作成してください。 ``` ### French ```yaml context: | Langue : Français Tous les artefacts doivent être rédigés en français. ``` ### German ```yaml context: | Sprache: Deutsch Alle Artefakte müssen auf Deutsch verfasst werden. ``` ## Tips ### Handle Technical Terms Decide how to handle technical terminology: ```yaml context: | Language: Japanese Write in Japanese, but: - Keep technical terms like "API", "REST", "GraphQL" in English - Code examples and file paths remain in English ``` ### Combine with Other Context Language settings work alongside your other project context: ```yaml schema: spec-driven context: | Language: Portuguese (pt-BR) All artifacts must be written in Brazilian Portuguese. Tech stack: TypeScript, React 18, Node.js 20 Database: PostgreSQL with Prisma ORM ``` ## Verification To verify your language config is working: ```bash # Check the instructions - should show your language context openspec instructions proposal --change my-change # Output will include your language context ``` ## Related Documentation - [Customization Guide](./customization.md) - Project configuration options - [Workflows Guide](./workflows.md) - Full workflow documentation ================================================ FILE: docs/opsx.md ================================================ # OPSX Workflow > Feedback welcome on [Discord](https://discord.gg/YctCnvvshC). ## What Is It? OPSX is now the standard workflow for OpenSpec. It's a **fluid, iterative workflow** for OpenSpec changes. No more rigid phases — just actions you can take anytime. ## Why This Exists The legacy OpenSpec workflow works, but it's **locked down**: - **Instructions are hardcoded** — buried in TypeScript, you can't change them - **All-or-nothing** — one big command creates everything, can't test individual pieces - **Fixed structure** — same workflow for everyone, no customization - **Black box** — when AI output is bad, you can't tweak the prompts **OPSX opens it up.** Now anyone can: 1. **Experiment with instructions** — edit a template, see if the AI does better 2. **Test granularly** — validate each artifact's instructions independently 3. **Customize workflows** — define your own artifacts and dependencies 4. **Iterate quickly** — change a template, test immediately, no rebuild ``` Legacy workflow: OPSX: ┌────────────────────────┐ ┌────────────────────────┐ │ Hardcoded in package │ │ schema.yaml │◄── You edit this │ (can't change) │ │ templates/*.md │◄── Or this │ ↓ │ │ ↓ │ │ Wait for new release │ │ Instant effect │ │ ↓ │ │ ↓ │ │ Hope it's better │ │ Test it yourself │ └────────────────────────┘ └────────────────────────┘ ``` **This is for everyone:** - **Teams** — create workflows that match how you actually work - **Power users** — tweak prompts to get better AI outputs for your codebase - **OpenSpec contributors** — experiment with new approaches without releases We're all still learning what works best. OPSX lets us learn together. ## The User Experience **The problem with linear workflows:** You're "in planning phase", then "in implementation phase", then "done". But real work doesn't work that way. You implement something, realize your design was wrong, need to update specs, continue implementing. Linear phases fight against how work actually happens. **OPSX approach:** - **Actions, not phases** — create, implement, update, archive — do any of them anytime - **Dependencies are enablers** — they show what's possible, not what's required next ``` proposal ──→ specs ──→ design ──→ tasks ──→ implement ``` ## Setup ```bash # Make sure you have openspec installed — skills are automatically generated 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 Project config lets you set defaults and inject project-specific context into all artifacts. ### Creating Config Config is created during `openspec init`, or manually: ```yaml # openspec/config.yaml schema: spec-driven context: | Tech stack: TypeScript, React, Node.js API conventions: RESTful, JSON responses Testing: Vitest for unit tests, Playwright for e2e Style: ESLint with Prettier, strict TypeScript rules: proposal: - Include rollback plan - Identify affected teams specs: - Use Given/When/Then format for scenarios design: - Include sequence diagrams for complex flows ``` ### Config Fields | Field | Type | Description | |-------|------|-------------| | `schema` | string | Default schema for new changes (e.g., `spec-driven`) | | `context` | string | Project context injected into all artifact instructions | | `rules` | object | Per-artifact rules, keyed by artifact ID | ### How It Works **Schema precedence** (highest to lowest): 1. CLI flag (`--schema `) 2. Change metadata (`.openspec.yaml` in change directory) 3. Project config (`openspec/config.yaml`) 4. Default (`spec-driven`) **Context injection:** - Context is prepended to every artifact's instructions - Wrapped in `...` tags - Helps AI understand your project's conventions **Rules injection:** - Rules are only injected for matching artifacts - Wrapped in `...` tags - Appear after context, before the template ### Artifact IDs by Schema **spec-driven** (default): - `proposal` — Change proposal - `specs` — Specifications - `design` — Technical design - `tasks` — Implementation tasks ### Config Validation - Unknown artifact IDs in `rules` generate warnings - Schema names are validated against available schemas - Context has a 50KB size limit - Invalid YAML is reported with line numbers ### Troubleshooting **"Unknown artifact ID in rules: X"** - Check artifact IDs match your schema (see list above) - Run `openspec schemas --json` to see artifact IDs for each schema **Config not being applied:** - Ensure file is at `openspec/config.yaml` (not `.yml`) - Check YAML syntax with a validator - Config changes take effect immediately (no restart needed) **Context too large:** - Context is limited to 50KB - Summarize or link to external docs instead ## Commands | Command | What it does | |---------|--------------| | `/opsx:propose` | Create a change and generate planning artifacts in one step (default quick path) | | `/opsx:explore` | Think through ideas, investigate problems, clarify requirements | | `/opsx:new` | Start a new change scaffold (expanded workflow) | | `/opsx:continue` | Create the next artifact (expanded workflow) | | `/opsx:ff` | Fast-forward planning artifacts (expanded workflow) | | `/opsx:apply` | Implement tasks, updating artifacts as needed | | `/opsx:verify` | Validate implementation against artifacts (expanded workflow) | | `/opsx:sync` | Sync delta specs to main (expanded workflow, optional) | | `/opsx:archive` | Archive when done | | `/opsx:bulk-archive` | Archive multiple completed changes (expanded workflow) | | `/opsx:onboard` | Guided walkthrough of an end-to-end change (expanded workflow) | ## Usage ### Explore an idea ``` /opsx:explore ``` Think through ideas, investigate problems, compare options. No structure required - just a thinking partner. When insights crystallize, transition to `/opsx:propose` (default) or `/opsx:new`/`/opsx:ff` (expanded). ### Start a new change ``` /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 ``` ### Create artifacts ``` /opsx:continue ``` Shows what's ready to create based on dependencies, then creates one artifact. Use repeatedly to build up your change incrementally. ``` /opsx:ff add-dark-mode ``` Creates all planning artifacts at once. Use when you have a clear picture of what you're building. ### Implement (the fluid part) ``` /opsx:apply ``` Works through tasks, checking them off as you go. If you're juggling multiple changes, you can run `/opsx:apply `; otherwise it should infer from the conversation and prompt you to choose if it can't tell. ### Finish up ``` /opsx:archive # Move to archive when done (prompts to sync specs if needed) ``` ## When to Update vs. Start Fresh You can always edit your proposal or specs before implementation. But when does refining become "this is different work"? ### What a Proposal Captures A proposal defines three things: 1. **Intent** — What problem are you solving? 2. **Scope** — What's in/out of bounds? 3. **Approach** — How will you solve it? The question is: which changed, and by how much? ### Update the Existing Change When: **Same intent, refined execution** - You discover edge cases you didn't consider - The approach needs tweaking but the goal is unchanged - Implementation reveals the design was slightly off **Scope narrows** - You realize full scope is too big, want to ship MVP first - "Add dark mode" → "Add dark mode toggle (system preference in v2)" **Learning-driven corrections** - Codebase isn't structured how you thought - A dependency doesn't work as expected - "Use CSS variables" → "Use Tailwind's dark: prefix instead" ### Start a New Change When: **Intent fundamentally changed** - The problem itself is different now - "Add dark mode" → "Add comprehensive theme system with custom colors, fonts, spacing" **Scope exploded** - Change grew so much it's essentially different work - Original proposal would be unrecognizable after updates - "Fix login bug" → "Rewrite auth system" **Original is completable** - The original change can be marked "done" - New work stands alone, not a refinement - Complete "Add dark mode MVP" → Archive → New change "Enhance dark mode" ### The Heuristics ``` ┌─────────────────────────────────────┐ │ Is this the same work? │ └──────────────┬──────────────────────┘ │ ┌──────────────────┼──────────────────┐ │ │ │ ▼ ▼ ▼ Same intent? >50% overlap? Can original Same problem? Same scope? be "done" without │ │ these changes? │ │ │ ┌────────┴────────┐ ┌──────┴──────┐ ┌───────┴───────┐ │ │ │ │ │ │ YES NO YES NO NO YES │ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ▼ UPDATE NEW UPDATE NEW UPDATE NEW ``` | Test | Update | New Change | |------|--------|------------| | **Identity** | "Same thing, refined" | "Different work" | | **Scope overlap** | >50% overlaps | <50% overlaps | | **Completion** | Can't be "done" without changes | Can finish original, new work stands alone | | **Story** | Update chain tells coherent story | Patches would confuse more than clarify | ### The Principle > **Update preserves context. New change provides clarity.** > > Choose update when the history of your thinking is valuable. > Choose new when starting fresh would be clearer than patching. Think of it like git branches: - Keep committing while working on the same feature - Start a new branch when it's genuinely new work - Sometimes merge a partial feature and start fresh for phase 2 ## What's Different? | | Legacy (`/openspec:proposal`) | OPSX (`/opsx:*`) | |---|---|---| | **Structure** | One big proposal document | Discrete artifacts with dependencies | | **Workflow** | Linear phases: plan → implement → archive | Fluid actions — do anything anytime | | **Iteration** | Awkward to go back | Update artifacts as you learn | | **Customization** | Fixed structure | Schema-driven (define your own artifacts) | **The key insight:** work isn't linear. OPSX stops pretending it is. ## 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 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ LEGACY WORKFLOW │ │ (Phase-Locked, All-or-Nothing) │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ PLANNING │ ───► │ IMPLEMENTING │ ───► │ ARCHIVING │ │ │ │ PHASE │ │ PHASE │ │ PHASE │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ /openspec:proposal /openspec:apply /openspec:archive │ │ │ │ • Creates ALL artifacts at once │ │ • Can't go back to update specs during implementation │ │ • Phase gates enforce linear progression │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────────────────┐ │ OPSX WORKFLOW │ │ (Fluid Actions, Iterative) │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌────────────────────────────────────────────┐ │ │ │ ACTIONS (not phases) │ │ │ │ │ │ │ │ new ◄──► continue ◄──► apply ◄──► archive │ │ │ │ │ │ │ │ │ │ │ │ └──────────┴───────────┴───────────┘ │ │ │ │ any order │ │ │ └────────────────────────────────────────────┘ │ │ │ │ • Create artifacts one at a time OR fast-forward │ │ • Update specs/design/tasks during implementation │ │ • Dependencies enable progress, phases don't exist │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` ### Component Architecture **Legacy workflow** uses hardcoded templates in TypeScript: ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ LEGACY WORKFLOW COMPONENTS │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ Hardcoded Templates (TypeScript strings) │ │ │ │ │ ▼ │ │ Tool-specific configurators/adapters │ │ │ │ │ ▼ │ │ Generated Command Files (.claude/commands/openspec/*.md) │ │ │ │ • Fixed structure, no artifact awareness │ │ • Change requires code modification + rebuild │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` **OPSX** uses external schemas and a dependency graph engine: ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ OPSX COMPONENTS │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ Schema Definitions (YAML) │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ name: spec-driven │ │ │ │ artifacts: │ │ │ │ - id: proposal │ │ │ │ generates: proposal.md │ │ │ │ requires: [] ◄── Dependencies │ │ │ │ - id: specs │ │ │ │ generates: specs/**/*.md ◄── Glob patterns │ │ │ │ requires: [proposal] ◄── Enables after proposal │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ Artifact Graph Engine │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ • Topological sort (dependency ordering) │ │ │ │ • State detection (filesystem existence) │ │ │ │ • Rich instruction generation (templates + context) │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ Skill Files (.claude/skills/openspec-*/SKILL.md) │ │ │ │ • Cross-editor compatible (Claude Code, Cursor, Windsurf) │ │ • Skills query CLI for structured data │ │ • Fully customizable via schema files │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` ### Dependency Graph Model Artifacts form a directed acyclic graph (DAG). Dependencies are **enablers**, not gates: ``` proposal (root node) │ ┌─────────────┴─────────────┐ │ │ ▼ ▼ specs design (requires: (requires: proposal) proposal) │ │ └─────────────┬─────────────┘ │ ▼ tasks (requires: specs, design) │ ▼ ┌──────────────┐ │ APPLY PHASE │ │ (requires: │ │ tasks) │ └──────────────┘ ``` **State transitions:** ``` BLOCKED ────────────────► READY ────────────────► DONE │ │ │ Missing All deps File exists dependencies are DONE on filesystem ``` ### Information Flow **Legacy workflow** — agent receives static instructions: ``` User: "/openspec:proposal" │ ▼ ┌─────────────────────────────────────────┐ │ Static instructions: │ │ • Create proposal.md │ │ • Create tasks.md │ │ • Create design.md │ │ • Create specs//spec.md │ │ │ │ No awareness of what exists or │ │ dependencies between artifacts │ └─────────────────────────────────────────┘ │ ▼ Agent creates ALL artifacts in one go ``` **OPSX** — agent queries for rich context: ``` User: "/opsx:continue" │ ▼ ┌──────────────────────────────────────────────────────────────────────────┐ │ Step 1: Query current state │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │ $ openspec status --change "add-auth" --json │ │ │ │ │ │ │ │ { │ │ │ │ "artifacts": [ │ │ │ │ {"id": "proposal", "status": "done"}, │ │ │ │ {"id": "specs", "status": "ready"}, ◄── First ready │ │ │ │ {"id": "design", "status": "ready"}, │ │ │ │ {"id": "tasks", "status": "blocked", "missingDeps": ["specs"]}│ │ │ │ ] │ │ │ │ } │ │ │ └────────────────────────────────────────────────────────────────────┘ │ │ │ │ Step 2: Get rich instructions for ready artifact │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │ $ openspec instructions specs --change "add-auth" --json │ │ │ │ │ │ │ │ { │ │ │ │ "template": "# Specification\n\n## ADDED Requirements...", │ │ │ │ "dependencies": [{"id": "proposal", "path": "...", "done": true}│ │ │ │ "unlocks": ["tasks"] │ │ │ │ } │ │ │ └────────────────────────────────────────────────────────────────────┘ │ │ │ │ Step 3: Read dependencies → Create ONE artifact → Show what's unlocked │ └──────────────────────────────────────────────────────────────────────────┘ ``` ### Iteration Model **Legacy workflow** — awkward to iterate: ``` ┌─────────┐ ┌─────────┐ ┌─────────┐ │/proposal│ ──► │ /apply │ ──► │/archive │ └─────────┘ └─────────┘ └─────────┘ │ │ │ ├── "Wait, the design is wrong" │ │ │ ├── Options: │ │ • Edit files manually (breaks context) │ │ • Abandon and start over │ │ • Push through and fix later │ │ │ └── No official "go back" mechanism │ └── Creates ALL artifacts at once ``` **OPSX** — natural iteration: ``` /opsx:new ───► /opsx:continue ───► /opsx:apply ───► /opsx:archive │ │ │ │ │ ├── "The design is wrong" │ │ │ │ │ ▼ │ │ Just edit design.md │ │ and continue! │ │ │ │ │ ▼ │ │ /opsx:apply picks up │ │ where you left off │ │ │ └── Creates ONE artifact, shows what's unlocked │ └── Scaffolds change, waits for direction ``` ### Custom Schemas Create custom workflows using the schema management commands: ```bash # Create a new schema from scratch (interactive) openspec schema init my-workflow # Or fork an existing schema as a starting point openspec schema fork spec-driven my-workflow # Validate your schema structure openspec schema validate my-workflow # See where a schema resolves from (useful for debugging) openspec schema which my-workflow ``` Schemas are stored in `openspec/schemas/` (project-local, version controlled) or `~/.local/share/openspec/schemas/` (user global). **Schema structure:** ``` openspec/schemas/research-first/ ├── schema.yaml └── templates/ ├── research.md ├── proposal.md └── tasks.md ``` **Example schema.yaml:** ```yaml name: research-first artifacts: - id: research # Added before proposal generates: research.md requires: [] - id: proposal generates: proposal.md requires: [research] # Now depends on research - id: tasks generates: tasks.md requires: [proposal] ``` **Dependency Graph:** ``` research ──► proposal ──► tasks ``` ### Summary | Aspect | Legacy | OPSX | |--------|----------|------| | **Templates** | Hardcoded TypeScript | External YAML + Markdown | | **Dependencies** | None (all at once) | DAG with topological sort | | **State** | Phase-based mental model | Filesystem existence | | **Customization** | Edit source, rebuild | Create schema.yaml | | **Iteration** | Phase-locked | Fluid, edit anything | | **Editor Support** | Tool-specific configurator/adapters | Single skills directory | ## Schemas Schemas define what artifacts exist and their dependencies. Currently available: - **spec-driven** (default): proposal → specs → design → tasks ```bash # List available schemas openspec schemas # See all schemas with their resolution sources openspec schema which --all # Create a new schema interactively openspec schema init my-workflow # Fork an existing schema for customization openspec schema fork spec-driven my-workflow # Validate schema structure before use openspec schema validate my-workflow ``` ## Tips - Use `/opsx:explore` to think through an idea before committing to a change - `/opsx:ff` when you know what you want, `/opsx:continue` when exploring - During `/opsx:apply`, if something's wrong — fix the artifact, then continue - Tasks track progress via checkboxes in `tasks.md` - Check status anytime: `openspec status --change "name"` ## Feedback This is rough. That's intentional — we're learning what works. Found a bug? Have ideas? Join us on [Discord](https://discord.gg/YctCnvvshC) or open an issue on [GitHub](https://github.com/Fission-AI/openspec/issues). ================================================ FILE: docs/supported-tools.md ================================================ # Supported Tools 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 selected tool, OpenSpec can install: 1. **Skills** (if delivery includes skills): `.../skills/openspec-*/SKILL.md` 2. **Commands** (if delivery includes commands): tool-specific `opsx-*` command files 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 (ID) | Skills path pattern | Command path pattern | |-----------|---------------------|----------------------| | Amazon Q Developer (`amazon-q`) | `.amazonq/skills/openspec-*/SKILL.md` | `.amazonq/prompts/opsx-.md` | | Antigravity (`antigravity`) | `.agent/skills/openspec-*/SKILL.md` | `.agent/workflows/opsx-.md` | | Auggie (`auggie`) | `.augment/skills/openspec-*/SKILL.md` | `.augment/commands/opsx-.md` | | Claude Code (`claude`) | `.claude/skills/openspec-*/SKILL.md` | `.claude/commands/opsx/.md` | | Cline (`cline`) | `.cline/skills/openspec-*/SKILL.md` | `.clinerules/workflows/opsx-.md` | | CodeBuddy (`codebuddy`) | `.codebuddy/skills/openspec-*/SKILL.md` | `.codebuddy/commands/opsx/.md` | | Codex (`codex`) | `.codex/skills/openspec-*/SKILL.md` | `$CODEX_HOME/prompts/opsx-.md`\* | | Continue (`continue`) | `.continue/skills/openspec-*/SKILL.md` | `.continue/prompts/opsx-.prompt` | | CoStrict (`costrict`) | `.cospec/skills/openspec-*/SKILL.md` | `.cospec/openspec/commands/opsx-.md` | | Crush (`crush`) | `.crush/skills/openspec-*/SKILL.md` | `.crush/commands/opsx/.md` | | Cursor (`cursor`) | `.cursor/skills/openspec-*/SKILL.md` | `.cursor/commands/opsx-.md` | | Factory Droid (`factory`) | `.factory/skills/openspec-*/SKILL.md` | `.factory/commands/opsx-.md` | | Gemini CLI (`gemini`) | `.gemini/skills/openspec-*/SKILL.md` | `.gemini/commands/opsx/.toml` | | GitHub Copilot (`github-copilot`) | `.github/skills/openspec-*/SKILL.md` | `.github/prompts/opsx-.prompt.md`\*\* | | iFlow (`iflow`) | `.iflow/skills/openspec-*/SKILL.md` | `.iflow/commands/opsx-.md` | | Kilo Code (`kilocode`) | `.kilocode/skills/openspec-*/SKILL.md` | `.kilocode/workflows/opsx-.md` | | Kiro (`kiro`) | `.kiro/skills/openspec-*/SKILL.md` | `.kiro/prompts/opsx-.prompt.md` | | OpenCode (`opencode`) | `.opencode/skills/openspec-*/SKILL.md` | `.opencode/commands/opsx-.md` | | Pi (`pi`) | `.pi/skills/openspec-*/SKILL.md` | `.pi/prompts/opsx-.md` | | Qoder (`qoder`) | `.qoder/skills/openspec-*/SKILL.md` | `.qoder/commands/opsx/.md` | | Qwen Code (`qwen`) | `.qwen/skills/openspec-*/SKILL.md` | `.qwen/commands/opsx-.toml` | | RooCode (`roocode`) | `.roo/skills/openspec-*/SKILL.md` | `.roo/commands/opsx-.md` | | Trae (`trae`) | `.trae/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use skill-based `/openspec-*` invocations) | | Windsurf (`windsurf`) | `.windsurf/skills/openspec-*/SKILL.md` | `.windsurf/workflows/opsx-.md` | \* 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 `--tools` (and optionally `--profile`): ```bash # Configure specific tools openspec init --tools claude,cursor # Configure all supported tools openspec init --tools all # Skip tool configuration openspec init --tools none # Override profile for this init run openspec init --profile core ``` **Available 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` ## Workflow-Dependent Installation OpenSpec installs workflow artifacts based on selected workflows: - **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` In other words, skill/command counts are profile-dependent and delivery-dependent, not fixed. ## Generated Skill Names 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 - [CLI Reference](cli.md) — Terminal commands - [Commands](commands.md) — Slash commands and skills - [Getting Started](getting-started.md) — First-time setup ================================================ FILE: docs/workflows.md ================================================ # Workflows This guide covers common workflow patterns for OpenSpec and when to use each one. For basic setup, see [Getting Started](getting-started.md). For command reference, see [Commands](commands.md). ## Philosophy: Actions, Not Phases Traditional workflows force you through phases: planning, then implementation, then done. But real work doesn't fit neatly into boxes. OPSX takes a different approach: ```text Traditional (phase-locked): PLANNING ────────► IMPLEMENTING ────────► DONE │ │ │ "Can't go back" │ └────────────────────┘ OPSX (fluid actions): proposal ──► specs ──► design ──► tasks ──► implement ``` **Key principles:** - **Actions, not phases** - Commands are things you can do, not stages you're stuck in - **Dependencies are enablers** - They show what's possible, not what's required next > **Customization:** OPSX workflows are driven by schemas that define artifact sequences. See [Customization](customization.md) for details on creating custom schemas. ## 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 When you know what you want to build and just need to execute: ```text /opsx:new ──► /opsx:ff ──► /opsx:apply ──► /opsx:verify ──► /opsx:archive ``` **Example conversation:** ```text You: /opsx:new add-logout-button AI: Created openspec/changes/add-logout-button/ Ready to create: proposal You: /opsx:ff AI: Creating all planning artifacts... ✓ proposal.md ✓ specs/ ✓ design.md ✓ tasks.md Ready for implementation! You: /opsx:apply AI: Working through tasks... ✓ Added logout button to header ✓ Implemented session clearing ✓ Added confirmation dialog All tasks complete! You: /opsx:archive AI: ✓ Merged specs ✓ Archived change ``` **Best for:** Small to medium features, bug fixes, straightforward changes. ### Exploratory When requirements are unclear or you need to investigate first: ```text /opsx:explore ──► /opsx:new ──► /opsx:continue ──► ... ──► /opsx:apply ``` **Example conversation:** ```text You: /opsx:explore AI: What would you like to explore? You: I want to improve page load performance but I'm not sure where the bottlenecks are. AI: Let me help investigate... [Analyzes bundle sizes, identifies slow queries, reviews component render patterns] I found three main bottlenecks: 1. Large unoptimized images 2. Synchronous data fetching in ProductList 3. Re-renders from context changes Which would you like to address first? You: Let's tackle the data fetching issue. You: /opsx:new optimize-product-list-fetching AI: Created change. Ready to create: proposal You: /opsx:continue AI: Creating proposal based on our exploration... [Writes proposal incorporating investigation insights] Ready to create: specs, design Which would you like next? You: /opsx:continue AI: Creating specs... ``` **Best for:** Performance optimization, debugging, architectural decisions, unclear requirements. ### Parallel Changes Work on multiple changes at once: ```text Change A: /opsx:new ──► /opsx:ff ──► /opsx:apply (in progress) │ context switch │ Change B: /opsx:new ──► /opsx:ff ──────► /opsx:apply ``` **Example conversation:** ```text You: I'm working on add-dark-mode but got pulled into a bug fix You: /opsx:new fix-login-redirect AI: Created openspec/changes/fix-login-redirect/ You: /opsx:ff AI: ✓ Created planning artifacts You: /opsx:apply AI: Working on fix-login-redirect... [Implements the fix] All tasks complete! You: /opsx:archive AI: ✓ Archived fix-login-redirect You: Let's get back to dark mode You: /opsx:apply add-dark-mode AI: Resuming add-dark-mode... Picking up at task 2.3: Update Header... ``` **Best for:** Parallel work streams, urgent interrupts, team collaboration. When you have multiple completed changes, use `/opsx:bulk-archive`: ```text You: /opsx:bulk-archive AI: Found 3 completed changes: - add-dark-mode (all tasks done) - fix-login-redirect (all tasks done) - update-footer (all tasks done) Checking for spec conflicts... ⚠ add-dark-mode and update-footer both touch specs/ui/ Inspecting codebase to resolve... Both changes are implemented. Will apply in chronological order. Archive all 3 changes? You: Yes AI: ✓ Archived add-dark-mode ✓ Archived fix-login-redirect ✓ Archived update-footer Specs merged in order: add-dark-mode → update-footer ``` Bulk archive detects when multiple changes touch the same specs and resolves conflicts by checking what's actually implemented. ### Completing a Change The recommended completion flow: ```text /opsx:apply ──► /opsx:verify ──► /opsx:archive │ │ validates prompts to sync implementation if needed ``` #### Verify: Check Your Work `/opsx:verify` validates implementation against your artifacts across three dimensions: ```text You: /opsx:verify AI: Verifying add-auth... COMPLETENESS ✓ All 12 tasks in tasks.md are checked ✓ All requirements in specs have corresponding code ⚠ Scenario "Session timeout after inactivity" not tested CORRECTNESS ✓ Implementation matches spec intent ✓ Edge cases from scenarios are handled ✓ Error states match spec definitions COHERENCE ✓ Design decisions reflected in code structure ✓ Naming conventions consistent with design.md ⚠ Design mentions "event-driven" but implementation uses polling SUMMARY ───────────────────────────── Critical issues: 0 Warnings: 2 Ready to archive: Yes (with warnings) Recommendations: 1. Add test for session timeout scenario 2. Consider refactoring to event-driven as designed, or update design.md ``` **What verify checks:** | Dimension | What it validates | |-----------|------------------| | Completeness | All tasks done, all requirements implemented, scenarios covered | | Correctness | Implementation matches spec intent, edge cases handled | | Coherence | Design decisions reflected in code, patterns consistent | Verify won't block archive, but it surfaces issues you might want to address first. #### Archive: Finalize the Change `/opsx:archive` completes the change and moves it to the archive: ```text You: /opsx:archive AI: Archiving add-auth... Artifact status: ✓ proposal.md exists ✓ specs/ exists ✓ design.md exists ✓ tasks.md exists (12/12 tasks complete) Delta specs: Not yet synced to main → Would you like to sync now? You: Yes AI: ✓ Synced specs to openspec/specs/auth/spec.md ✓ Moved to openspec/changes/archive/2025-01-24-add-auth/ Change archived successfully. ``` Archive will prompt if specs aren't synced. It won't block on incomplete tasks, but it will warn you. ## When to Use What ### `/opsx:ff` vs `/opsx:continue` | Situation | Use | |-----------|-----| | Clear requirements, ready to build | `/opsx:ff` | | Exploring, want to review each step | `/opsx:continue` | | Want to iterate on proposal before specs | `/opsx:continue` | | Time pressure, need to move fast | `/opsx:ff` | | Complex change, want control | `/opsx:continue` | **Rule of thumb:** If you can describe the full scope upfront, use `/opsx:ff`. If you're figuring it out as you go, use `/opsx:continue`. ### When to Update vs Start Fresh A common question: when is updating an existing change okay, and when should you start a new one? **Update the existing change when:** - Same intent, refined execution - Scope narrows (MVP first, rest later) - Learning-driven corrections (codebase isn't what you expected) - Design tweaks based on implementation discoveries **Start a new change when:** - Intent fundamentally changed - Scope exploded to different work entirely - Original change can be marked "done" standalone - Patches would confuse more than clarify ```text ┌─────────────────────────────────────┐ │ Is this the same work? │ └──────────────┬──────────────────────┘ │ ┌──────────────────┼──────────────────┐ │ │ │ ▼ ▼ ▼ Same intent? >50% overlap? Can original Same problem? Same scope? be "done" without │ │ these changes? │ │ │ ┌────────┴────────┐ ┌──────┴──────┐ ┌───────┴───────┐ │ │ │ │ │ │ YES NO YES NO NO YES │ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ▼ UPDATE NEW UPDATE NEW UPDATE NEW ``` **Example: "Add dark mode"** - "Need to also support custom themes" → New change (scope exploded) - "System preference detection is harder than expected" → Update (same intent) - "Let's ship toggle first, add preferences later" → Update then archive, then new change ## Best Practices ### Keep Changes Focused One logical unit of work per change. If you're doing "add feature X and also refactor Y", consider two separate changes. **Why it matters:** - Easier to review and understand - Cleaner archive history - Can ship independently - Simpler rollback if needed ### Use `/opsx:explore` for Unclear Requirements Before committing to a change, explore the problem space: ```text You: /opsx:explore AI: What would you like to explore? You: How should we handle rate limiting for our API? AI: Let me investigate your current setup and options... [Researches codebase, considers patterns] I see three approaches we could take: 1. Middleware-based (simple, per-endpoint) 2. Redis-backed (scalable, shared state) 3. Token bucket per user (fair, complex) Your current stack suggests #1 or #2. What's your scale? ``` Exploration clarifies thinking before you create artifacts. ### Verify Before Archiving Use `/opsx:verify` to check implementation matches artifacts: ```text You: /opsx:verify AI: Verifying add-dark-mode... ✓ All tasks in tasks.md are checked ✓ Requirements in specs have corresponding code ✓ Design decisions are reflected in implementation Ready to archive! ``` Catches mismatches before you close out the change. ### Name Changes Clearly Good names make `openspec list` useful: ```text Good: Avoid: add-dark-mode feature-1 fix-login-redirect update optimize-product-query changes implement-2fa wip ``` ## Command Quick Reference For full command details and options, see [Commands](commands.md). | Command | Purpose | When to Use | |---------|---------|-------------| | `/opsx:propose` | Create change + planning artifacts | Fast default path (`core` profile) | | `/opsx:explore` | Think through ideas | Unclear requirements, investigation | | `/opsx:new` | Start a change scaffold | Expanded mode, explicit artifact control | | `/opsx:continue` | Create next artifact | Expanded mode, step-by-step artifact creation | | `/opsx:ff` | Create all planning artifacts | Expanded mode, clear scope | | `/opsx:apply` | Implement tasks | Ready to write code | | `/opsx:verify` | Validate implementation | Expanded mode, before archiving | | `/opsx:sync` | Merge delta specs | Expanded mode, optional | | `/opsx:archive` | Complete the change | All work finished | | `/opsx:bulk-archive` | Archive multiple changes | Expanded mode, parallel work | ## Next Steps - [Commands](commands.md) - Full command reference with options - [Concepts](concepts.md) - Deep dive into specs, artifacts, and schemas - [Customization](customization.md) - Create custom workflows ================================================ FILE: eslint.config.js ================================================ import tseslint from 'typescript-eslint'; export default tseslint.config( { files: ['src/**/*.ts'], extends: [...tseslint.configs.recommended], rules: { // Prevent static imports of @inquirer modules to avoid pre-commit hook hangs. // These modules have side effects that can keep the Node.js event loop alive // when stdin is piped. Use dynamic import() instead. // See: https://github.com/Fission-AI/OpenSpec/issues/367 'no-restricted-imports': [ 'error', { patterns: [ { group: ['@inquirer/*'], message: 'Use dynamic import() for @inquirer modules to prevent pre-commit hook hangs. See #367.', }, ], }, ], // Disable rules that need broader cleanup - focus on critical issues only '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-unused-vars': 'off', 'no-empty': 'off', 'prefer-const': 'off', }, }, { // init.ts is dynamically imported from cli/index.ts, so static @inquirer // imports there are safe - they won't be loaded at CLI startup files: ['src/core/init.ts'], rules: { 'no-restricted-imports': 'off', }, }, { ignores: ['dist/**', 'node_modules/**', '*.js', '*.mjs'], } ); ================================================ FILE: flake.nix ================================================ { description = "OpenSpec - AI-native system for spec-driven development"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; }; outputs = { self, nixpkgs }: let supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system); in { packages = forAllSystems ( system: let pkgs = nixpkgs.legacyPackages.${system}; inherit (pkgs) lib; in { default = pkgs.stdenv.mkDerivation (finalAttrs: { pname = "openspec"; version = (builtins.fromJSON (builtins.readFile ./package.json)).version; src = lib.fileset.toSource { root = ./.; fileset = lib.fileset.unions [ ./src ./bin ./schemas ./scripts ./test ./package.json ./pnpm-lock.yaml ./tsconfig.json ./build.js ./vitest.config.ts ./vitest.setup.ts ./eslint.config.js ]; }; pnpmDeps = pkgs.fetchPnpmDeps { inherit (finalAttrs) pname version src; pnpm = pkgs.pnpm_9; fetcherVersion = 3; hash = "sha256-9s2kdvd7svK4hofnD66HkDc86WTQeayfF5y7L2dmjNg="; }; nativeBuildInputs = with pkgs; [ nodejs_20 npmHooks.npmInstallHook pnpmConfigHook pnpm_9 ]; buildPhase = '' runHook preBuild pnpm run build runHook postBuild ''; dontNpmPrune = true; meta = with pkgs.lib; { description = "AI-native system for spec-driven development"; homepage = "https://github.com/Fission-AI/OpenSpec"; license = licenses.mit; maintainers = [ ]; mainProgram = "openspec"; }; }); } ); apps = forAllSystems (system: { default = { type = "app"; program = "${self.packages.${system}.default}/bin/openspec"; }; }); devShells = forAllSystems ( system: let pkgs = nixpkgs.legacyPackages.${system}; in { default = pkgs.mkShell { buildInputs = with pkgs; [ nodejs_20 pnpm_9 ]; shellHook = '' echo "OpenSpec development environment" echo "Node version: $(node --version)" echo "pnpm version: $(pnpm --version)" echo "Run 'pnpm install' to install dependencies" ''; }; } ); }; } ================================================ FILE: openspec/changes/IMPLEMENTATION_ORDER.md ================================================ # Implementation Order and Dependencies ## Required Implementation Sequence The following changes must be implemented in this specific order due to dependencies: ### Phase 1: Foundation **1. add-zod-validation** (No dependencies) - Creates all core schemas (RequirementSchema, ScenarioSchema, SpecSchema, ChangeSchema, DeltaSchema) - Implements markdown parser utilities - Implements validation infrastructure and rules - Establishes validation patterns used by all commands - Must be completed first ### Phase 2: Change Commands **2. add-change-commands** (Depends on: add-zod-validation) - Imports ChangeSchema and DeltaSchema from zod validation - Reuses markdown parsing utilities - Implements change command with built-in validation - Uses validation infrastructure for change validate subcommand - Cannot start until schemas and validation exist ### Phase 3: Spec Commands **3. add-spec-commands** (Depends on: add-zod-validation, add-change-commands) - Imports RequirementSchema, ScenarioSchema, SpecSchema from zod validation - Reuses markdown parsing utilities - Implements spec command with built-in validation - Uses validation infrastructure for spec validate subcommand - Builds on patterns established by change commands ## Dependency Graph ``` add-zod-validation ↓ add-change-commands ↓ add-spec-commands ``` ## Key Dependencies ### Shared Code Dependencies 1. **Schemas**: All schemas created in add-zod-validation, used by both command implementations 2. **Validation**: Infrastructure created in add-zod-validation, integrated into both commands 3. **Parsers**: Markdown parsing utilities created in add-zod-validation, used by both commands ### File Dependencies - `src/core/schemas/*.schema.ts` (created by add-zod-validation) → imported by both commands - `src/core/validation/validator.ts` (created by add-zod-validation) → used by both commands - `src/core/parsers/markdown-parser.ts` (created by add-zod-validation) → used by both commands ## Implementation Notes ### For Developers 1. Complete each phase fully before moving to the next 2. Run tests after each phase to ensure stability 3. The legacy `list` command remains functional throughout ### For CI/CD 1. Each change can be validated independently 2. Integration tests should run after each phase 3. Full system tests required after Phase 3 ### Parallel Work Opportunities Within each phase, the following can be done in parallel: - **Phase 1**: Schema design, validation rules, and parser implementation - **Phase 2**: Change command features and legacy compatibility work - **Phase 3**: Spec command features and final integration ================================================ FILE: openspec/changes/add-artifact-regeneration-support/proposal.md ================================================ # Add Artifact Regeneration Support ## Problem Currently, there is **no way to regenerate artifacts** in the OPSX workflow: - `/opsx:apply` just reads whatever's on disk - `/opsx:continue` only creates the NEXT artifact - won't touch existing ones If you edit `design.md` after `tasks.md` exists, your only options are: 1. Delete tasks.md manually, then run `/opsx:continue` 2. Edit tasks.md manually The documentation claims you can "update artifacts mid-flight and continue" but there's no mechanism that actually supports this. ## Proposed Solution Two parts: ### Part 1: Staleness Detection Add artifact staleness detection to `/opsx:apply`: 1. **Track modification times**: When generating an artifact, record the mtime of its dependencies 2. **Detect staleness**: When `/opsx:apply` runs, check if upstream artifacts (design.md, specs) have been modified since tasks.md was generated 3. **Prompt user**: If stale, ask: "Design was modified after tasks were generated. Would you like to regenerate tasks with `/opsx:continue`?" ## User Experience ### Vision: Seamless Mid-Flight Correction This is the workflow we want to enable (currently documented but not supported): ``` You: /opsx:apply AI: Working through tasks... ✓ Task 1.1: Created caching layer ✓ Task 1.2: Added cache invalidation Working on 1.3: Implement TTL... I noticed the design assumes Redis, but your project uses in-memory caching. Should I update the design? You: Yes, update it to use the existing cache module. AI: Updated design.md to use CacheManager from src/cache/ Updated tasks.md with revised implementation steps Continuing implementation... ✓ Task 1.3: Implemented TTL using CacheManager ... ``` **No restart needed.** Just update the artifact and continue. ### Staleness Warning UX When user manually edits an upstream artifact: ``` $ /opsx:apply ⚠️ Detected changes to upstream artifacts: - design.md modified 5 minutes ago (after tasks.md was generated) Options: 1. Regenerate tasks (recommended) 2. Continue anyway with current tasks 3. Cancel > ``` ### Part 2: Regeneration Capability Add a way to regenerate specific artifacts: ```bash # Option A: Flag on continue /opsx:continue --regenerate tasks # Option B: Separate command /opsx:regenerate tasks # Option C: Interactive prompt when staleness detected /opsx:apply # "Design changed. Regenerate tasks? [y/N]" ``` ## Technical Approach ### Option A: Metadata File Store `.openspec-meta.json` in change directory: ```json { "tasks.md": { "generated_at": "2025-01-24T10:00:00Z", "dependencies": { "design.md": "2025-01-24T09:55:00Z", "specs/feature/spec.md": "2025-01-24T09:50:00Z" } } } ``` ### Option B: Frontmatter Add YAML frontmatter to generated artifacts: ```markdown --- generated_at: 2025-01-24T10:00:00Z depends_on: - design.md@2025-01-24T09:55:00Z --- # Tasks ... ``` ### Option C: Git-based Use git to detect if upstream files changed since downstream was last modified. No extra metadata needed but requires git. ## Non-Goals - Automatic regeneration (user should always choose) - Blocking apply entirely (just warn) - Tracking code file changes (only artifact dependencies) ## Dependencies - Should be implemented after `fix-midflight-update-docs` so docs are accurate first - Could be combined with that change if desired ## Success Criteria - User is warned when applying with stale artifacts - Clear path to regenerate if needed - No false positives (only warn when genuinely stale) - Documentation claims become actually true ================================================ FILE: openspec/changes/add-change-stacking-awareness/.openspec.yaml ================================================ schema: spec-driven created: 2026-02-21 ================================================ FILE: openspec/changes/add-change-stacking-awareness/proposal.md ================================================ ## 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 ` 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 ================================================ FILE: openspec/changes/add-change-stacking-awareness/specs/change-creation/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-change-stacking-awareness/specs/change-stacking-workflow/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-change-stacking-awareness/specs/cli-change/spec.md ================================================ ## 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 ` - **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 ` 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 ================================================ FILE: openspec/changes/add-change-stacking-awareness/specs/openspec-conventions/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-change-stacking-awareness/tasks.md ================================================ ## 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 ` 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 ================================================ FILE: openspec/changes/add-global-install-scope/.openspec.yaml ================================================ schema: spec-driven created: 2026-02-21 ================================================ FILE: openspec/changes/add-global-install-scope/design.md ================================================ ## 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. ================================================ FILE: openspec/changes/add-global-install-scope/proposal.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-global-install-scope/specs/ai-tool-paths/spec.md ================================================ ## 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 `//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` ================================================ FILE: openspec/changes/add-global-install-scope/specs/cli-config/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-global-install-scope/specs/cli-init/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-global-install-scope/specs/cli-update/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-global-install-scope/specs/command-generation/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-global-install-scope/specs/global-config/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-global-install-scope/specs/installation-scope/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-global-install-scope/tasks.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-qa-smoke-harness/.openspec.yaml ================================================ schema: spec-driven created: 2026-02-20 ================================================ FILE: openspec/changes/add-qa-smoke-harness/proposal.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-qa-smoke-harness/specs/developer-qa-workflow/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-tool-command-surface-capabilities/.openspec.yaml ================================================ schema: spec-driven created: 2026-02-19 ================================================ FILE: openspec/changes/add-tool-command-surface-capabilities/proposal.md ================================================ ## 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. ================================================ FILE: openspec/changes/add-tool-command-surface-capabilities/specs/cli-init/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-tool-command-surface-capabilities/specs/cli-update/spec.md ================================================ ## 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 ================================================ FILE: openspec/changes/add-tool-command-surface-capabilities/tasks.md ================================================ ## 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` ================================================ FILE: openspec/changes/archive/2025-01-11-add-update-command/design.md ================================================ # Technical Design ## Architecture Decisions ### Simplicity First - No version tracking - always update when commanded - Full replacement for OpenSpec-managed files only (e.g., `openspec/README.md`) - Marker-based updates for user-owned files (e.g., `CLAUDE.md`) - Templates bundled with package - no network required - Minimal error handling - only check prerequisites ### Template Strategy - Use existing template utilities - `readmeTemplate` from `src/core/templates/readme-template.ts` for `openspec/README.md` - `TemplateManager.getClaudeTemplate()` for `CLAUDE.md` - Directory name is fixed to `openspec` (from `OPENSPEC_DIR_NAME`) ### File Operations - Use async utilities for consistency - `FileSystemUtils.writeFile` for `openspec/README.md` - `FileSystemUtils.updateFileWithMarkers` for `CLAUDE.md` - No atomic operations needed - users have git - Check directory existence before proceeding ## Implementation ### Update Command (`src/core/update.ts`) ```typescript export class UpdateCommand { async execute(projectPath: string): Promise { const openspecDirName = OPENSPEC_DIR_NAME; const openspecPath = path.join(projectPath, openspecDirName); // 1. Check openspec directory exists if (!await FileSystemUtils.directoryExists(openspecPath)) { throw new Error(`No OpenSpec directory found. Run 'openspec init' first.`); } // 2. Update README.md (full replacement) const readmePath = path.join(openspecPath, 'README.md'); await FileSystemUtils.writeFile(readmePath, readmeTemplate); // 3. Update CLAUDE.md (marker-based) const claudePath = path.join(projectPath, 'CLAUDE.md'); const claudeContent = TemplateManager.getClaudeTemplate(); await FileSystemUtils.updateFileWithMarkers( claudePath, claudeContent, OPENSPEC_MARKERS.start, OPENSPEC_MARKERS.end ); // 4. Success message (ASCII-safe, checkmark optional by terminal) console.log('Updated OpenSpec instructions'); } } ``` ## Why This Approach ### Benefits - **Dead simple**: ~40 lines of code total - **Fast**: No version checks, minimal parsing - **Predictable**: Same result every time; idempotent - **Maintainable**: Reuses existing utilities ### Trade-offs Accepted - No version tracking (unnecessary complexity) - Full overwrite only for OpenSpec-managed files - Marker-managed updates for user-owned files ## Error Handling Only handle critical errors: - Missing `openspec` directory → throw error handled by CLI to present a friendly message - File write failures → let errors bubble up to CLI ## Testing Strategy Manual smoke tests are sufficient initially: 1. Run `openspec init` in a test project 2. Modify both files (including custom content around markers in `CLAUDE.md`) 3. Run `openspec update` 4. Verify `openspec/README.md` fully replaced; `CLAUDE.md` OpenSpec block updated without altering user content outside markers 5. Run the command twice to verify idempotency and no duplicate markers 6. Test with missing `openspec` directory (expect failure) ================================================ FILE: openspec/changes/archive/2025-01-11-add-update-command/proposal.md ================================================ # Add Update Command ## Why Users need a way to update their local OpenSpec instructions (README.md and CLAUDE.md) when the OpenSpec package releases new versions with improved AI agent instructions or structural conventions. ## What Changes - Add new `openspec update` CLI command that updates OpenSpec instructions - Replace `openspec/README.md` with the latest template - Safe because this file is fully OpenSpec-managed - Update only the OpenSpec-managed block in `CLAUDE.md` using markers - Preserve all user content outside markers - If `CLAUDE.md` is missing, create it with the managed block - Display success message after update (ASCII-safe): "Updated OpenSpec instructions" - A leading checkmark MAY be shown when the terminal supports it - Operation is idempotent (re-running yields identical results) ## Impact - Affected specs: `cli-update` (new capability) - Affected code: - `src/core/update.ts` (new command class, mirrors `InitCommand` placement) - `src/cli/index.ts` (register new command) - Uses existing templates via `TemplateManager` and `readmeTemplate` ## Out of Scope - No `.openspec/config.json` is introduced by this change. The default directory name `openspec` is used. ================================================ FILE: openspec/changes/archive/2025-01-11-add-update-command/specs/cli-update/spec.md ================================================ # Update Command Specification ## Purpose As a developer using OpenSpec, I want to update the OpenSpec instructions in my project when new versions are released, so that I can benefit from improvements to AI agent instructions. ## Core Requirements ### Update Behavior The update command SHALL update OpenSpec instruction files to the latest templates. WHEN a user runs `openspec update` THEN the command SHALL: - Check if the `openspec` directory exists - Replace `openspec/README.md` with the latest template (complete replacement) - Update the OpenSpec-managed block in `CLAUDE.md` using markers - Preserve user content outside markers - Create `CLAUDE.md` if missing - Display ASCII-safe success message: "Updated OpenSpec instructions" ### Prerequisites The command SHALL require: - An existing `openspec` directory (created by `openspec init`) IF the `openspec` directory does not exist THEN: - Display error: "No OpenSpec directory found. Run 'openspec init' first." - Exit with code 1 ### File Handling The update command SHALL: - Completely replace `openspec/README.md` with the latest template - Update only the OpenSpec-managed block in `CLAUDE.md` using markers - Use the default directory name `openspec` - Be idempotent (repeated runs have no additional effect) ## Edge Cases ### File Permissions IF file write fails THEN let the error bubble up naturally with file path. ### Missing CLAUDE.md IF CLAUDE.md doesn't exist THEN create it with the template content. ### Custom Directory Name Not supported in this change. The default directory name `openspec` SHALL be used. ## Success Criteria Users SHALL be able to: - Update OpenSpec instructions with a single command - Get the latest AI agent instructions - See clear confirmation of the update The update process SHALL be: - Simple and fast (no version checking) - Predictable (same result every time) - Self-contained (no network required) ================================================ FILE: openspec/changes/archive/2025-01-11-add-update-command/tasks.md ================================================ # Implementation Tasks ## 1. Update Command Implementation - [x] 1.1 Create `src/core/update.ts` with `UpdateCommand` class - [x] 1.2 Check if `openspec` directory exists (use `FileSystemUtils.directoryExists`) - [x] 1.3 Write `readmeTemplate` to `openspec/README.md` using `FileSystemUtils.writeFile` - [x] 1.4 Update `CLAUDE.md` using markers via `FileSystemUtils.updateFileWithMarkers` and `TemplateManager.getClaudeTemplate()` - [x] 1.5 Display ASCII-safe success message: `Updated OpenSpec instructions` ## 2. CLI Integration - [x] 2.1 Register `update` command in `src/cli/index.ts` - [x] 2.2 Add command description: `Update OpenSpec instruction files` - [x] 2.3 Handle errors with `ora().fail(...)` and exit code 1 (missing `openspec` directory, file write errors) ## 3. Testing - [x] 3.1 Verify `openspec/README.md` is fully replaced with latest template - [x] 3.2 Verify `CLAUDE.md` OpenSpec block updates without altering user content outside markers - [x] 3.3 Verify idempotency (running twice yields identical files, no duplicate markers) - [x] 3.4 Verify error when `openspec` directory is missing with friendly message - [x] 3.5 Verify success message displays properly in ASCII-only terminals ================================================ FILE: openspec/changes/archive/2025-01-13-add-list-command/proposal.md ================================================ # Add List Command to OpenSpec CLI ## Why Developers need visibility into available changes and their status to understand the project's evolution and pending work. ## What Changes - Add `openspec list` command that displays all changes in the changes/ directory - Show each change name with task completion count (e.g., "add-auth: 3/5 tasks") - Display completion status indicator (✓ for fully complete, progress for partial) - Skip the archive/ subdirectory to focus on active changes - Simple table output for easy scanning ## Impact - Affected specs: New capability `cli-list` will be added - Affected code: - `src/cli/index.ts` - Add list command - `src/core/list.ts` - New file with directory scanning and task parsing (~60 lines) ================================================ FILE: openspec/changes/archive/2025-01-13-add-list-command/specs/cli-list/spec.md ================================================ # List Command Specification ## Purpose The `openspec list` command SHALL provide developers with a quick overview of all active changes in the project, showing their names and task completion status. ## Behavior ### Command Execution WHEN `openspec list` is executed THEN scan the `openspec/changes/` directory for change directories AND exclude the `archive/` subdirectory from results AND parse each change's `tasks.md` file to count task completion ### Task Counting WHEN parsing a `tasks.md` file THEN count tasks matching these patterns: - Completed: Lines containing `- [x]` - Incomplete: Lines containing `- [ ]` AND calculate total tasks as the sum of completed and incomplete ### Output Format WHEN displaying the list THEN show a table with columns: - Change name (directory name) - Task progress (e.g., "3/5 tasks" or "✓ Complete") - Status indicator: - `✓` for fully completed changes (all tasks done) - Progress fraction for partial completion Example output: ``` Changes: add-auth-feature 3/5 tasks update-api-docs ✓ Complete fix-validation 0/2 tasks add-list-command 1/4 tasks ``` ### Empty State WHEN no active changes exist (only archive/ or empty changes/) THEN display: "No active changes found." ### Error Handling IF a change directory has no `tasks.md` file THEN display the change with "No tasks" status IF `openspec/changes/` directory doesn't exist THEN display error: "No OpenSpec changes directory found. Run 'openspec init' first." AND exit with code 1 ### Sorting Changes SHALL be displayed in alphabetical order by change name for consistency. ## Why Developers need a quick way to: - See what changes are in progress - Identify which changes are ready to archive - Understand the overall project evolution status - Get a bird's-eye view without opening multiple files This command provides that visibility with minimal effort, following OpenSpec's philosophy of simplicity and clarity. ================================================ FILE: openspec/changes/archive/2025-01-13-add-list-command/tasks.md ================================================ # Implementation Tasks ## 1. Core Implementation - [x] 1.1 Create `src/core/list.ts` with list logic - [x] 1.1.1 Implement directory scanning (exclude archive/) - [x] 1.1.2 Implement task counting from tasks.md files - [x] 1.1.3 Format output as simple table - [x] 1.2 Add list command to CLI in `src/cli/index.ts` - [x] 1.2.1 Register `openspec list` command - [x] 1.2.2 Connect to list.ts implementation ## 2. Error Handling - [x] 2.1 Handle missing openspec/changes/ directory - [x] 2.2 Handle changes without tasks.md files - [x] 2.3 Handle empty changes directory ## 3. Testing - [x] 3.1 Add tests for list functionality - [x] 3.1.1 Test with multiple changes - [x] 3.1.2 Test with completed changes - [x] 3.1.3 Test with no changes - [x] 3.1.4 Test error conditions ## 4. Documentation - [x] 4.1 Update CLI help text with list command - [x] 4.2 Add list command to README if applicable ================================================ FILE: openspec/changes/archive/2025-08-05-initialize-typescript-project/design.md ================================================ # Technical Design ## Technology Choices ### TypeScript Configuration - **Strict mode**: Enable all strict type checking for better AI understanding - **Target**: ES2022 for modern JavaScript features - **Module**: ES2022 for modern ESM support - **Module Resolution**: Node for proper package resolution - **Output**: dist/ directory for compiled JavaScript - **Source Maps**: Enable for debugging TypeScript directly - **Declaration Files**: Generate .d.ts files for type definitions - **ES Module Interop**: true for better CommonJS compatibility - **Skip Lib Check**: false to ensure all types are validated ### Package Structure ``` openspec ├── bin/ # CLI entry point ├── dist/ # Compiled JavaScript ├── src/ # TypeScript source │ ├── cli/ # Command implementations │ ├── core/ # Core OpenSpec logic │ └── utils/ # Shared utilities ├── package.json ├── tsconfig.json └── build.js # Build script ``` ### Dependency Strategy - **Minimal dependencies**: Only essential packages - **commander**: Industry-standard CLI framework - **@inquirer/prompts**: Modern prompting library - **No heavy frameworks**: Direct, readable implementation ### Build Approach - Native TypeScript compilation via tsc - Simple build.js script for packaging - No complex build toolchain needed - ESM output with proper .js extensions in imports ### Development Workflow 1. `pnpm install` - Install dependencies 2. `pnpm run build` - Compile TypeScript 3. `pnpm run dev` - Development mode 4. `pnpm link` - Test CLI locally ### Node.js Requirements - **Minimum version**: Node.js 20.19.0 - **Recommended**: Node.js 22 LTS - **Rationale**: Full ESM support without flags, modern JavaScript features ### ESM Configuration - **Package type**: `"type": "module"` in package.json - **File extensions**: Use .js extensions in TypeScript imports (compiles correctly) - **Top-level await**: Available for cleaner async initialization - **Future-proof**: Aligns with JavaScript standards ### TypeScript Best Practices - **All code in TypeScript**: No .js files in src/, only .ts - **Explicit types**: Prefer explicit typing over inference where it adds clarity - **Interfaces over types**: Use interfaces for object shapes, types for unions/aliases - **No any**: Strict mode prevents implicit any, use unknown when needed - **Async/await**: Modern async patterns throughout ================================================ FILE: openspec/changes/archive/2025-08-05-initialize-typescript-project/proposal.md ================================================ # Initialize TypeScript Project ## Why The OpenSpec project needs a proper TypeScript foundation to build the minimal CLI that helps developers set up OpenSpec file structures and keep AI instructions updated. ## What Changes - Create TypeScript project configuration with ESM modules (package.json, tsconfig.json) - Set up the base directory structure for the CLI implementation - Configure build scripts and development tooling - Add essential dependencies for CLI development - Create .gitignore for Node.js/TypeScript projects - Set minimum Node.js version to 20.19.0 for native ESM support ## Impact - Affected specs: None (initial project setup) - Affected code: None (greenfield project) - New directories: src/, dist/, node_modules/ - New files: package.json, tsconfig.json, .gitignore, build.js ================================================ FILE: openspec/changes/archive/2025-08-05-initialize-typescript-project/tasks.md ================================================ # Tasks ## 1. Project Configuration - [x] 1.1 Create package.json with project metadata, scripts, and ESM configuration - [x] 1.2 Configure TypeScript with tsconfig.json for ESM output - [x] 1.3 Add .gitignore for Node.js/TypeScript projects - [x] 1.4 Set Node.js engine requirement to >=20.19.0 ## 2. Directory Structure - [x] 2.1 Create src/ directory for source code - [x] 2.2 Create src/cli/ for CLI commands - [x] 2.3 Create src/core/ for core OpenSpec logic - [x] 2.4 Create src/utils/ for shared utilities ## 3. Build Configuration - [x] 3.1 Create build.js for native TypeScript compilation - [x] 3.2 Configure development scripts (build, dev) - [x] 3.3 Set up package entry points with ESM exports - [x] 3.4 Configure proper file extensions handling for ESM ## 4. Initial Dependencies - [x] 4.1 Add TypeScript as dev dependency - [x] 4.2 Add commander for CLI framework - [x] 4.3 Add @inquirer/prompts for user interaction - [x] 4.4 Add necessary type definitions ================================================ FILE: openspec/changes/archive/2025-08-06-add-init-command/design.md ================================================ # Technical Design for Init Command ## Architecture Overview The init command follows a modular architecture with clear separation of concerns: ``` CLI Layer (src/cli/index.ts) ↓ Core Logic (src/core/init.ts) ↓ Templates (src/core/templates/) ↓ File System Utils (src/utils/file-system.ts) ``` ## Key Design Decisions ### 1. Template Management **Decision**: Store templates as TypeScript modules rather than separate files **Rationale**: - Ensures templates are bundled with the compiled code - Allows for dynamic content insertion - Type-safe template handling - No need for complex file path resolution ### 2. Interactive vs Non-Interactive Mode **Decision**: Support both interactive (default) and non-interactive modes **Rationale**: - Interactive mode for developer experience - Non-interactive for CI/CD and automation - Flags: `--yes` to accept defaults, `--no-input` for full automation ### 3. Directory Structure Creation **Decision**: Create all directories upfront, then populate files **Rationale**: - Fail fast if permissions issues - Clear transaction boundary - Easier to clean up on failure ### 4. Error Handling Strategy **Decision**: Implement rollback on failure **Rationale**: - Prevent partial installations - Clear error states - Better user experience ## Implementation Details ### File System Operations ```typescript // Atomic directory creation with rollback interface InitTransaction { createdPaths: string[]; rollback(): Promise; commit(): Promise; } ``` ### Template System ```typescript interface Template { path: string; content: string | ((context: ProjectContext) => string); } interface ProjectContext { projectName: string; description: string; techStack: string[]; conventions: string; } ``` ### CLI Command Structure ```bash openspec init [path] # Initialize in specified path (default: current directory) --yes # Accept all defaults --no-input # Skip all prompts --force # Overwrite existing OpenSpec directory --dry-run # Show what would be created ``` ## Security Considerations 1. **Path Traversal**: Sanitize all user-provided paths 2. **File Permissions**: Check write permissions before starting 3. **Existing Files**: Never overwrite without explicit --force flag 4. **Template Injection**: Sanitize user inputs in templates ## Future Extensibility The design supports future enhancements: - Custom template sources - Project type presets (API, web app, library) - Migration from other documentation systems - Integration with version control systems ================================================ FILE: openspec/changes/archive/2025-08-06-add-init-command/proposal.md ================================================ # Add Init Command for OpenSpec ## Why Projects need a simple way to adopt OpenSpec conventions. Currently, users must manually create the directory structure and understand all the conventions, which creates friction for adoption. An init command would enable instant OpenSpec setup with proper structure and guidance. ## What Changes - Add `openspec init` CLI command that creates the complete OpenSpec directory structure - Generate template files (README.md with AI instructions, project.md template) - Interactive prompt to select which AI tools to configure (Claude Code initially, others marked as "coming soon") - Support for multiple AI coding assistants with extensible plugin architecture - Smart file updates using content markers to preserve existing configurations - Custom directory naming with `--dir` flag - Validation to prevent overwriting existing OpenSpec structures - Clear error messages with helpful guidance (e.g., suggesting 'openspec update' for existing structures) - Display actionable next steps after successful initialization ### Breaking Changes - None - this is a new feature ## Impact - Affected specs: None (new feature) - Affected code: - src/cli/index.ts (add init command) - src/core/init.ts (new - initialization logic) - src/core/templates/ (new - template files) - src/core/configurators/ (new - AI tool plugins) - src/utils/file-system.ts (new - file operations) ================================================ FILE: openspec/changes/archive/2025-08-06-add-init-command/specs/cli-init/spec.md ================================================ # CLI Init Specification ## Purpose The `openspec init` command SHALL create a complete OpenSpec directory structure in any project, enabling immediate adoption of OpenSpec conventions with support for multiple AI coding assistants. ## Behavior ### Progress Indicators WHEN executing initialization steps THEN validate environment silently in background (no output unless error) AND display progress with ora spinners: - Show spinner: "⠋ Creating OpenSpec structure..." - Then success: "✔ OpenSpec structure created" - Show spinner: "⠋ Configuring AI tools..." - Then success: "✔ AI tools configured" ### Directory Creation WHEN `openspec init` is executed THEN create the following directory structure: ``` openspec/ ├── project.md ├── README.md ├── specs/ └── changes/ └── archive/ ``` ### File Generation The command SHALL generate: - `README.md` containing complete OpenSpec instructions for AI assistants - `project.md` with project context template ### AI Tool Configuration WHEN run interactively THEN prompt user to select AI tools to configure: - Claude Code (updates/creates CLAUDE.md with OpenSpec markers) - Cursor (future) - Aider (future) ### AI Tool Configuration Details WHEN Claude Code is selected THEN create or update `CLAUDE.md` in the project root directory (not inside openspec/) WHEN CLAUDE.md does not exist THEN create new file with OpenSpec content wrapped in markers: ```markdown # OpenSpec Project This document provides instructions for AI coding assistants on how to use OpenSpec conventions for spec-driven development. Follow these rules precisely when working on OpenSpec-enabled projects. This project uses OpenSpec for spec-driven development. Specifications are the source of truth. See @openspec/README.md for detailed conventions and guidelines. ``` WHEN CLAUDE.md already exists THEN preserve all existing content AND insert OpenSpec content at the beginning of the file using markers AND ensure markers don't duplicate if they already exist The marker system SHALL: - Use `` to mark the beginning of managed content - Use `` to mark the end of managed content - Allow OpenSpec to update its content without affecting user customizations - Preserve all content outside the markers intact WHY use markers: - Users may have existing CLAUDE.md instructions they want to keep - OpenSpec can update its instructions in future versions - Clear boundary between OpenSpec-managed and user-managed content ### Interactive Mode WHEN run THEN prompt user with: "Which AI tool do you use?" AND show single-select menu with available tools: - Claude Code AND show disabled options as "coming soon" (not selectable): - Cursor (coming soon) - Aider (coming soon) - Continue (coming soon) User navigation: - Use arrow keys to move between options - Press Enter to select the highlighted option ### Safety Checks WHEN `openspec/` directory already exists THEN display error with ora fail indicator: "✖ Error: OpenSpec seems to already be initialized. Use 'openspec update' to update the structure." WHEN checking initialization feasibility THEN verify write permissions in the target directory silently AND only display error if permissions are insufficient ### Success Output WHEN initialization completes successfully THEN display actionable prompts for AI-driven workflow: ``` ✔ OpenSpec initialized successfully! Next steps - Copy these prompts to Claude: ──────────────────────────────────────────────────────────── 1. Populate your project context: "Please read openspec/project.md and help me fill it out with details about my project, tech stack, and conventions" 2. Create your first change proposal: "I want to add [YOUR FEATURE HERE]. Please create an OpenSpec change proposal for this feature" 3. Learn the OpenSpec workflow: "Please explain the OpenSpec workflow from openspec/README.md and how I should work with you on this project" ──────────────────────────────────────────────────────────── ``` The prompts SHALL: - Be copy-pasteable for immediate use with AI tools - Guide users through the AI-driven workflow - Replace placeholder text ([YOUR FEATURE HERE]) with actual features ### Exit Codes - 0: Success - 1: General error (including when OpenSpec directory already exists) - 2: Insufficient permissions (reserved for future use) - 3: User cancelled operation (reserved for future use) ## Why Manual creation of OpenSpec structure is error-prone and creates adoption friction. A standardized init command ensures: - Consistent structure across all projects - Proper AI instruction files are always included - Quick onboarding for new projects - Clear conventions from the start ================================================ FILE: openspec/changes/archive/2025-08-06-add-init-command/tasks.md ================================================ # Implementation Tasks for Init Command ## 1. Core Infrastructure - [x] 1.1 Create src/utils/file-system.ts with directory/file creation utilities - [x] 1.2 Create src/core/templates/index.ts for template management - [x] 1.3 Create src/core/init.ts with main initialization logic - [x] 1.4 Create src/core/config.ts for configuration management ## 2. Template Files - [x] 2.1 Create src/core/templates/readme-template.ts with OpenSpec README content - [x] 2.2 Create src/core/templates/project-template.ts with customizable project.md - [x] 2.3 Create src/core/templates/claude-template.ts for CLAUDE.md content with markers ## 3. AI Tool Configurators - [x] 3.1 Create src/core/configurators/base.ts with ToolConfigurator interface - [x] 3.2 Create src/core/configurators/claude.ts for Claude Code configuration - [x] 3.3 Create src/core/configurators/registry.ts for tool registration - [x] 3.4 Implement marker-based file updates for existing configurations ## 4. Init Command Implementation - [x] 4.1 Add init command to src/cli/index.ts using Commander - [x] 4.2 Implement AI tool selection with multi-select prompt (Claude Code available, others "coming soon") - requires at least one selection - [x] 4.3 Add validation for existing OpenSpec directories with helpful error message - [x] 4.4 Implement directory structure creation - [x] 4.5 Implement file generation with templates and markers ## 5. User Experience - [x] 5.1 Add colorful console output for better UX - [x] 5.2 Implement progress indicators (Step 1/3, 2/3, 3/3) - [x] 5.3 Add success message with actionable next steps (edit project.md, create first change) - [x] 5.4 Add error handling with helpful messages ## 6. Testing and Documentation - [x] 6.1 Add unit tests for file system utilities - [x] 6.2 Add unit tests for marker-based file updates - [x] 6.3 Add integration tests for init command - [x] 6.4 Update package.json with proper bin configuration - [x] 6.5 Test the built CLI command end-to-end ================================================ FILE: openspec/changes/archive/2025-08-06-adopt-future-state-storage/proposal.md ================================================ # Adopt Future State Storage for OpenSpec Changes ## Why The current approach of storing spec changes as diff files (`.spec.md.diff`) creates friction for both humans and AI. Diff syntax with `+` and `-` prefixes makes specs hard to read, AI tools struggle with the format when understanding future state, and GitHub can't show nice comparisons between current and proposed specs in different folders. ## What Changes - Change from storing diffs (`patches/[capability]/spec.md.diff`) to storing complete future state (`specs/[capability]/spec.md`) - Update all documentation to reflect new storage format - Migrate existing `add-init-command` change to new format - Add new `openspec-conventions` capability to document these conventions ## Impact - Affected specs: New `openspec-conventions` capability - Affected code: - openspec/README.md (lines 85-108) - docs/PRD.md (lines 376-382, 778-783) - docs/openspec-walkthrough.md (lines 58-62, 112-126) - openspec/changes/add-init-command/ (migration needed) ================================================ FILE: openspec/changes/archive/2025-08-06-adopt-future-state-storage/specs/openspec-conventions/spec.md ================================================ # OpenSpec Conventions Specification ## Purpose OpenSpec conventions SHALL define how system capabilities are documented, how changes are proposed and tracked, and how specifications evolve over time. This meta-specification serves as the source of truth for OpenSpec's own conventions. ## Core Principles The system SHALL follow these principles: - Specs reflect what IS currently built and deployed - Changes contain proposals for what SHOULD be changed - AI drives the documentation process - Specs are living documentation kept in sync with deployed code ## Directory Structure WHEN an OpenSpec project is initialized THEN it SHALL have this structure: ``` openspec/ ├── project.md # Project-specific context ├── README.md # AI assistant instructions ├── specs/ # Current deployed capabilities │ └── [capability]/ # Single, focused capability │ ├── spec.md # WHAT and WHY │ └── design.md # HOW (optional, for established patterns) └── changes/ # Proposed changes ├── [change-name]/ # Descriptive change identifier │ ├── proposal.md # Why, what, and impact │ ├── tasks.md # Implementation checklist │ ├── design.md # Technical decisions (optional) │ └── specs/ # Complete future state │ └── [capability]/ │ └── spec.md # Clean markdown (no diff syntax) └── archive/ # Completed changes └── YYYY-MM-DD-[name]/ ``` ## Change Storage Convention ### Future State Storage WHEN creating a change proposal THEN store the complete future state of affected specs AND use clean markdown without diff syntax The `changes/[name]/specs/` directory SHALL contain: - Complete spec files as they will exist after the change - Clean markdown without `+` or `-` prefixes - All formatting and structure of the final intended state ### Proposal Format WHEN documenting what changes THEN the proposal SHALL explicitly describe each change: ```markdown **[Section or Behavior Name]** - From: [current state/requirement] - To: [future state/requirement] - Reason: [why this change is needed] - Impact: [breaking/non-breaking, who's affected] ``` This explicit format compensates for not having inline diffs and ensures reviewers understand exactly what will change. ## Change Lifecycle The change process SHALL follow these states: 1. **Propose**: AI creates change with future state specs and explicit proposal 2. **Review**: Humans review proposal and future state 3. **Approve**: Change is approved for implementation 4. **Implement**: Follow tasks.md checklist (can span multiple PRs) 5. **Deploy**: Changes are deployed to production 6. **Update**: Specs in `specs/` are updated to match deployed reality 7. **Archive**: Change is moved to `archive/YYYY-MM-DD-[name]/` ## Viewing Changes WHEN reviewing proposed changes THEN reviewers can compare using: - GitHub PR diff view when changes are committed - Command line: `diff -u specs/[capability]/spec.md changes/[name]/specs/[capability]/spec.md` - Any visual diff tool comparing current vs future state The system relies on tools to generate diffs rather than storing them. ## Capability Naming Capabilities SHALL use: - Verb-noun patterns (e.g., `user-auth`, `payment-capture`) - Hyphenated lowercase names - Singular focus (one responsibility per capability) - No nesting (flat structure under `specs/`) ## When Changes Require Proposals A proposal SHALL be created for: - New features or capabilities - Breaking changes to existing behavior - Architecture or pattern changes - Performance optimizations that change behavior - Security updates affecting access patterns A proposal is NOT required for: - Bug fixes restoring intended behavior - Typos or formatting fixes - Non-breaking dependency updates - Adding tests for existing behavior - Documentation clarifications ## Why This Approach Clean future state storage provides: - **Readability**: No diff syntax pollution - **AI-compatibility**: Standard markdown that AI tools understand - **Simplicity**: No special parsing or processing needed - **Tool-agnostic**: Any diff tool can show changes - **Clear intent**: Explicit proposals document reasoning ================================================ FILE: openspec/changes/archive/2025-08-06-adopt-future-state-storage/tasks.md ================================================ # Implementation Tasks ## 1. Update Core Documentation - [x] 1.1 Update openspec/README.md section on "Creating a Change Proposal" - [x] Replace `patches/` with `specs/` in directory structure - [x] Update step 3 to show storing complete future state - [x] Remove diff syntax instructions (+/- prefixes) ## 2. Migrate Existing Change - [x] 2.1 Convert add-init-command change to new format - [x] Create `specs/cli-init/spec.md` with clean content (no diff markers) - [x] Delete old `patches/` directory - [x] 2.2 Test that the migrated change is clear and reviewable ## 3. Update Documentation Examples - [x] 3.1 Update docs/PRD.md - [x] Fix directory structure examples (lines 376-382) - [x] Update archive examples (lines 778-783) - [x] Ensure consistency throughout - [x] 3.2 Update docs/openspec-walkthrough.md - [x] Replace diff examples with future state examples - [x] Ensure the walkthrough reflects new approach ## 4. Create New Spec - [x] 4.1 Finalize openspec-conventions spec in main specs/ directory - [x] Document the future state storage approach - [x] Include examples of good proposals - [x] Make it the source of truth for conventions ## 5. Validation - [x] 5.1 Verify all documentation is consistent - [x] 5.2 Test creating a new change with the new approach - [x] 5.3 Ensure GitHub PR view shows diffs clearly ## 6. Deployment - [x] 6.1 Get approval for this change - [x] 6.2 Implement all tasks above - [x] 6.3 After deployment, archive this change with completion date ================================================ FILE: openspec/changes/archive/2025-08-11-add-complexity-guidelines/proposal.md ================================================ # Add Complexity Management Guidelines ## Why OpenSpec currently lacks guidance on managing complexity, leading to over-engineered solutions when simple ones suffice. ## What Changes - Add "Start Simple" section to openspec/README.md with default minimalism rules - Add complexity triggers to help identify when complexity is justified - Enhance AI assistant instructions in CLAUDE.md to bias toward simplicity ## Impact - Affected specs: None (documentation only) - Affected code: openspec/README.md, CLAUDE.md ================================================ FILE: openspec/changes/archive/2025-08-11-add-complexity-guidelines/specs/openspec-docs/README.md ================================================ # OpenSpec Instructions This document provides instructions for AI coding assistants on how to use OpenSpec conventions for spec-driven development. Follow these rules precisely when working on OpenSpec-enabled projects. ## Core Principle OpenSpec is an AI-native system for change-driven development where: - **Specs** (`specs/`) reflect what IS currently built and deployed - **Changes** (`changes/`) contain proposals for what SHOULD be changed - **AI drives the process** - You generate proposals, humans review and approve - **Specs are living documentation** - Always kept in sync with deployed code ## Start Simple **Default to minimal implementations:** - New features should be <100 lines of code initially - Use the simplest solution that works - Avoid premature optimization (no caching, parallelization, or complex patterns without proven need) - Choose boring technology over cutting-edge solutions **Complexity triggers** - Only add complexity when you have: - **Performance data** showing current solution is too slow - **Scale requirements** with specific numbers (>1000 users, >100MB data) - **Multiple use cases** requiring the same abstraction - **Regulatory compliance** mandating specific patterns - **Security threats** that simple solutions cannot address When triggered, document the specific justification in your change proposal. ## Directory Structure ``` openspec/ ├── project.md # Project-specific context (tech stack, conventions) ├── README.md # This file - OpenSpec instructions ├── specs/ # Current truth - what IS built │ ├── [capability]/ # Single, focused capability │ │ ├── spec.md # WHAT the capability does and WHY │ │ └── design.md # HOW it's built (established patterns) │ └── ... ├── changes/ # Proposed changes - what we're CHANGING │ ├── [change-name]/ │ │ ├── proposal.md # Why, what, impact (consolidated) │ │ ├── tasks.md # Implementation checklist │ │ ├── design.md # Technical decisions (optional, for complex changes) │ │ └── specs/ # Future state of affected specs │ │ └── [capability]/ │ │ └── spec.md # Clean markdown (no diff syntax) │ └── archive/ # Completed changes (dated) ``` ### Capability Organization **Use capabilities, not features** - Each directory under `specs/` represents a single, focused responsibility: - **Verb-noun naming**: `user-auth`, `payment-capture`, `order-checkout` - **10-minute rule**: Each capability should be understandable in <10 minutes - **Single purpose**: If it needs "AND" to describe it, split it Examples: ``` ✅ GOOD: user-auth, user-sessions, payment-capture, payment-refunds ❌ BAD: users, payments, core, misc ``` ## Key Behavioral Rules ### 1. Always Start by Reading Before any task: 1. **Read relevant specs** in `specs/[capability]/spec.md` to understand current state 2. **Check pending changes** in `changes/` directory for potential conflicts 3. **Read project.md** for project-specific conventions ### 2. When to Create Change Proposals **ALWAYS create a change proposal for:** - New features or functionality - Breaking changes (API changes, schema updates) - Architecture changes or new patterns - Performance optimizations that change behavior - Security updates affecting auth/access patterns - Any change requiring multiple steps or affecting multiple systems **SKIP proposals for:** - Bug fixes that restore intended behavior - Typos, formatting, or comment updates - Dependency updates (unless breaking) - Configuration or environment variable changes - Adding tests for existing behavior - Documentation fixes **Complexity assessment:** - If your solution requires >100 lines of new code, justify the complexity - If adding dependencies, frameworks, or architectural patterns, document why simpler alternatives won't work - Default to single-file implementations until proven insufficient ### 3. Creating a Change Proposal When a user requests a significant change: ```bash # 1. Create the change directory openspec/changes/[descriptive-name]/ # 2. Generate proposal.md with all context ## Why [1-2 sentences on the problem/opportunity] ## What Changes [Bullet list of changes, including breaking changes] ## Impact - Affected specs: [list capabilities that will change] - Affected code: [list key files/systems] # 3. Create future state specs for ALL affected capabilities # - Store complete spec files as they will exist after the change # - Use clean markdown without diff syntax (+/- prefixes) # - Include all formatting and structure of the final intended state specs/ └── [capability]/ └── spec.md # 4. Create tasks.md with implementation steps ## 1. [Task Group] - [ ] 1.1 [Specific task] - [ ] 1.2 [Specific task] # 5. For complex changes, add design.md [Technical decisions and trade-offs] ``` ### 4. The Change Lifecycle 1. **Propose** → Create change directory with all documentation 2. **Review** → User reviews and approves the proposal 3. **Implement** → Follow the approved tasks.md (can be multiple PRs) 4. **Deploy** → User confirms deployment 5. **Update Specs** → Sync specs/ with new reality (IF the change affects system capabilities) 6. **Archive** → Move to `changes/archive/YYYY-MM-DD-[name]/` ### 5. Implementing Changes When implementing an approved change: 1. Follow the tasks.md checklist exactly 2. **Mark completed tasks** in tasks.md as you finish them (e.g., `- [x] 1.1 Task completed`) 3. Ensure code matches the proposed behavior 4. Update any affected tests 5. **Keep change in `changes/` directory** - do NOT archive in implementation PR **Multiple Implementation PRs:** - Changes can be implemented across multiple PRs - Each PR should update tasks.md to mark what was completed - Different developers can work on different task groups - Example: PR #1 completes tasks 1.1-1.3, PR #2 completes tasks 2.1-2.4 ### 6. Updating Specs and Archiving After Deployment **Create a separate PR after deployment** that: 1. Moves change to `changes/archive/YYYY-MM-DD-[name]/` 2. Updates relevant files in `specs/` to reflect new reality (if needed) 3. If design.md exists, incorporates proven patterns into `specs/[capability]/design.md` This ensures changes are only archived when truly complete and deployed. ### 7. Types of Changes That Don't Require Specs Some changes only affect development infrastructure and don't need specs: - Initial project setup (package.json, tsconfig.json, etc.) - Development tooling changes (linters, formatters, build tools) - CI/CD configuration - Development dependencies For these changes: 1. Implement → Deploy → Mark tasks complete → Archive 2. Skip the "Update Specs" step entirely ### What Deserves a Spec? Ask yourself: - Is this a system capability that users or other systems interact with? - Does it have ongoing behavior that needs documentation? - Would a new developer need to understand this to work with the system? If NO to all → No spec needed (likely just tooling/infrastructure) ## Understanding Specs vs Code ### Specs Document WHAT and WHY ```markdown # Authentication Spec Users SHALL authenticate with email and password. WHEN credentials are valid THEN issue JWT token. WHEN credentials are invalid THEN return generic error. WHY: Prevent user enumeration attacks. ``` ### Code Documents HOW ```javascript // Implementation details const user = await db.users.findOne({ email }); const valid = await bcrypt.compare(password, user.hashedPassword); ``` **Key Distinction**: Specs capture intent, constraints, and decisions that aren't obvious from code. ## Common Scenarios ### New Feature Request ``` User: "Add password reset functionality" You should: 1. Read specs/user-auth/spec.md 2. Check changes/ for pending auth changes 3. Create changes/add-password-reset/ with proposal 4. Wait for approval before implementing ``` ### Bug Fix ``` User: "Getting null pointer error when bio is empty" You should: 1. Check if spec says bios are optional 2. If yes → Fix directly (it's a bug) 3. If no → Create change proposal (it's a behavior change) ``` ### Infrastructure Setup ``` User: "Initialize TypeScript project" You should: 1. Create change proposal for TypeScript setup 2. Implement configuration files (PR #1) 3. Mark tasks complete in tasks.md 4. After deployment, create separate PR to archive (no specs update needed - this is tooling, not a capability) ``` ## Summary Workflow 1. **Receive request** → Determine if it needs a change proposal 2. **Read current state** → Check specs and pending changes 3. **Create proposal** → Generate complete change documentation 4. **Get approval** → User reviews the proposal 5. **Implement** → Follow approved tasks, mark completed items in tasks.md 6. **Deploy** → User deploys the implementation 7. **Archive PR** → Create separate PR to: - Move change to archive - Update specs if needed - Mark change as complete ## PR Workflow Examples ### Single Developer, Simple Change ``` PR #1: Implementation - Implement all tasks - Update tasks.md marking items complete - Get merged and deployed PR #2: Archive (after deployment) - Move changes/feature-x/ → changes/archive/2025-01-15-feature-x/ - Update specs if needed ``` ### Multiple Developers, Complex Change ``` PR #1: Alice implements auth components - Complete tasks 1.1, 1.2, 1.3 - Update tasks.md marking these complete PR #2: Bob implements UI components - Complete tasks 2.1, 2.2 - Update tasks.md marking these complete PR #3: Alice fixes integration issues - Complete remaining task 1.4 - Update tasks.md [Deploy all changes] PR #4: Archive - Move to archive with deployment date - Update specs to reflect new auth flow ``` ### Key Rules - **Never archive in implementation PRs** - changes aren't done until deployed - **Always update tasks.md** - shows accurate progress - **One archive PR per change** - clear completion boundary - **Archive PR includes spec updates** - keeps specs current ## Capability Organization Best Practices ### Naming Capabilities - Use **verb-noun** patterns: `user-auth`, `payment-capture`, `order-checkout` - Be specific: `payment-capture` not just `payments` - Keep flat: Avoid nesting capabilities within capabilities - Singular focus: If you need "AND" to describe it, split it ### When to Split Capabilities Split when you have: - Multiple unrelated API endpoints - Different user personas or actors - Separate deployment considerations - Independent evolution paths #### Capability Boundary Guidelines - Would you import these separately? → Separate capabilities - Different deployment cadence? → Separate capabilities - Different teams own them? → Separate capabilities - Shared data models are OK, shared business logic means combine Examples: - user-auth (login/logout) vs user-sessions (token management) → SEPARATE - payment-capture vs payment-refunds → SEPARATE (different workflows) - user-profile vs user-settings → COMBINE (same data model, same owner) ### Cross-Cutting Concerns For system-wide policies (rate limiting, error handling, security), document them in: - `project.md` for project-wide conventions - Within relevant capability specs where they apply - Or create a dedicated capability if complex enough (e.g., `api-rate-limiting/`) ### Examples of Well-Organized Capabilities ``` specs/ ├── user-auth/ # Login, logout, password reset ├── user-sessions/ # Token management, refresh ├── user-profile/ # Profile CRUD operations ├── payment-capture/ # Processing payments ├── payment-refunds/ # Handling refunds └── order-checkout/ # Checkout workflow ``` For detailed guidance, see the [Capability Organization Guide](../docs/capability-organization.md). ## Common Scenarios and Clarifications ### Decision Ambiguity: Bug vs Behavior Change When specs are missing or ambiguous: - If NO spec exists → Treat current code behavior as implicit spec, require proposal - If spec is VAGUE → Require proposal to clarify spec alongside fix - If code and spec DISAGREE → Spec is truth, code is buggy (fix without proposal) - If unsure → Default to creating a proposal (safer option) Example: ``` User: "The API returns 404 for missing users but should return 400" AI: Is this a bug (spec says 400) or behavior change (spec says 404)? ``` ### When You Don't Know the Scope It's OK to explore first! Tell the user you need to investigate, then create an informed proposal. ### Exploration Phase (When Needed) BEFORE creating proposal, you may need exploration when: - User request is vague or high-level - Multiple implementation approaches exist - Scope is unclear without seeing code Exploration checklist: 1. Tell user you need to explore first 2. Use Grep/Read to understand current state 3. Create initial proposal based on findings 4. Refine with user feedback Example: ``` User: "Add caching to improve performance" AI: "Let me explore the codebase to understand the current architecture and identify caching opportunities." [After exploration] AI: "Based on my analysis, I've identified three areas where caching would help. Here's my proposal..." ``` ### When No Specs Exist Treat current code as implicit spec. Your proposal should document current state AND proposed changes. ### When in Doubt Default to creating a proposal. It's easier to skip an unnecessary proposal than fix an undocumented change. ### AI Workflow Adaptations Task tracking with OpenSpec: - Track exploration tasks separately from implementation - Document proposal creation steps as you go - Keep implementation tasks separate until proposal approved Parallel operations encouraged: - Read multiple specs simultaneously - Check multiple pending changes at once - Batch related searches for efficiency Progress communication: - "Exploring codebase to understand scope..." - "Creating proposal based on findings..." - "Implementing approved changes..." ### For AI Assistants - **Bias toward simplicity** - Propose the minimal solution that works - Use your exploration tools liberally before proposing - Batch operations for efficiency - Communicate your progress - It's OK to revise proposals based on discoveries - **Question complexity** - If your solution feels complex, simplify first ## Edge Case Handling ### Multi-Capability Changes Create ONE proposal that: - Lists all affected capabilities - Shows changes per capability - Has unified task list - Gets approved as a whole ### Outdated Specs If specs clearly outdated: 1. Create proposal to update specs to match reality 2. Implement new feature in separate proposal 3. OR combine both in one proposal with clear sections ### Emergency Hotfixes For critical production issues: 1. Announce: "This is an emergency fix" 2. Implement fix immediately 3. Create retroactive proposal 4. Update specs after deployment 5. Tag with [EMERGENCY] in archive ### Pure Refactoring No proposal needed for: - Code formatting/style - Internal refactoring (same API) - Performance optimization (same behavior) - Adding types to untyped code Proposal REQUIRED for: - API changes (even if compatible) - Database schema changes - Architecture changes - New dependencies ### Observability Additions No proposal needed for: - Adding log statements - New metrics/traces - Debugging additions - Error tracking Proposal REQUIRED if: - Changes log format/structure - Adds new monitoring service - Changes what's logged (privacy) ## Remember - You are the process driver - automate documentation burden - Specs must always reflect deployed reality - Changes are proposed, not imposed - Impact analysis prevents surprises - **Simplicity is the power** - just markdown files, minimal solutions - Start simple, add complexity only when justified By following these conventions, you enable true spec-driven development where documentation stays current, changes are traceable, and evolution is intentional. ================================================ FILE: openspec/changes/archive/2025-08-11-add-complexity-guidelines/tasks.md ================================================ # Implementation Tasks ## 1. Update OpenSpec README - [x] 1.1 Add "Start Simple" section after Core Principle - [x] 1.2 Add complexity triggers to "When to Create Change Proposals" section - [x] 1.3 Update AI workflow guidance to emphasize minimal implementations ## 2. Update CLAUDE.md - [x] 2.1 Add complexity management rules to project instructions ================================================ FILE: openspec/changes/archive/2025-08-13-add-archive-command/proposal.md ================================================ ## Why Need a command to archive completed changes to the archive folder with proper date prefixing, following OpenSpec conventions. Currently changes must be manually moved and renamed. ## What Changes - Add new `archive` command to CLI that moves changes to `changes/archive/YYYY-MM-DD-[change-name]/` - Check for incomplete tasks before archiving and warn user - Allow interactive selection of change to archive - Prevent archiving if target directory already exists - Update main specs from the change's future state specs (copy from `changes/[name]/specs/` to `openspec/specs/`) - Show confirmation prompt before updating specs, displaying which specs will be created/updated - Support `--yes` flag to skip confirmations for automation ## Impact - Affected specs: cli-archive (new) - Affected code: src/cli/index.ts, src/core/archive.ts (new) ================================================ FILE: openspec/changes/archive/2025-08-13-add-archive-command/specs/cli-archive/spec.md ================================================ # CLI Archive Command Specification ## Purpose The archive command moves completed changes from the active changes directory to the archive folder with date-based naming, following OpenSpec conventions. ## Command Syntax ```bash openspec archive [change-name] [--yes|-y] ``` Options: - `--yes`, `-y`: Skip confirmation prompts (for automation) ## Behavior ### Change Selection WHEN no change-name is provided THEN display interactive list of available changes (excluding archive/) AND allow user to select one WHEN change-name is provided THEN use that change directly AND validate it exists ### Task Completion Check The command SHALL scan the change's tasks.md file for incomplete tasks (marked with `- [ ]`) WHEN incomplete tasks are found THEN display all incomplete tasks to the user AND prompt for confirmation to continue AND default to "No" for safety WHEN all tasks are complete OR no tasks.md exists THEN proceed with archiving without prompting ### Archive Process The archive operation SHALL: 1. Create archive/ directory if it doesn't exist 2. Generate target name as `YYYY-MM-DD-[change-name]` using current date 3. Check if target directory already exists 4. Update main specs from the change's future state specs (see Spec Update Process below) 5. Move the entire change directory to the archive location WHEN target archive already exists THEN fail with error message AND do not overwrite existing archive WHEN move succeeds THEN display success message with archived name and list of updated specs ### Spec Update Process Before moving the change to archive, the command SHALL update main specs to reflect the deployed reality: WHEN the change contains specs in `changes/[name]/specs/` THEN: 1. Analyze which specs will be affected by comparing with existing specs 2. Display a summary of spec updates to the user (see Confirmation Behavior below) 3. Prompt for confirmation unless `--yes` flag is provided 4. If confirmed, for each capability spec in the change directory: - Copy the spec from `changes/[name]/specs/[capability]/spec.md` to `openspec/specs/[capability]/spec.md` - Create the target directory structure if it doesn't exist - Overwrite existing spec files (specs represent current reality, change specs are the new reality) - Track which specs were updated for the success message WHEN no specs exist in the change THEN skip the spec update step AND proceed with archiving ### Confirmation Behavior The spec update confirmation SHALL: - Display a clear summary showing: - Which specs will be created (new capabilities) - Which specs will be updated (existing capabilities) - The source path for each spec - Format the confirmation prompt as: ``` The following specs will be updated: NEW specs to be created: - cli-archive (from changes/add-archive-command/specs/cli-archive/spec.md) EXISTING specs to be updated: - cli-init (from changes/update-init-command/specs/cli-init/spec.md) Update 2 specs and archive 'add-archive-command'? [y/N]: ``` - Default to "No" for safety (require explicit "y" or "yes") - Skip confirmation when `--yes` or `-y` flag is provided WHEN user declines the confirmation THEN abort the entire archive operation AND display message: "Archive cancelled. No changes were made." AND exit with non-zero status code ## Error Handling SHALL handle the following error conditions: - Missing openspec/changes/ directory - Change not found - Archive target already exists - File system permissions issues ## Why These Decisions **Interactive selection**: Reduces typing and helps users see available changes **Task checking**: Prevents accidental archiving of incomplete work **Date prefixing**: Maintains chronological order and prevents naming conflicts **No overwrite**: Preserves historical archives and prevents data loss **Spec updates before archiving**: Specs in the main directory represent current reality; when a change is deployed and archived, its future state specs become the new reality and must replace the main specs **Confirmation for spec updates**: Provides visibility into what will change, prevents accidental overwrites, and ensures users understand the impact before specs are modified **--yes flag for automation**: Allows CI/CD pipelines to archive without interactive prompts while maintaining safety by default for manual use ================================================ FILE: openspec/changes/archive/2025-08-13-add-archive-command/tasks.md ================================================ # Implementation Tasks ## 1. Core Implementation - [ ] 1.1 Create `src/core/archive.ts` with ArchiveCommand class - [ ] 1.1.1 Implement change selection (interactive if not provided) - [ ] 1.1.2 Implement incomplete task checking from tasks.md - [ ] 1.1.3 Implement confirmation prompt for incomplete tasks - [ ] 1.1.4 Implement spec update functionality - [ ] 1.1.4.1 Detect specs in change directory - [ ] 1.1.4.2 Compare with existing main specs - [ ] 1.1.4.3 Display summary of new vs updated specs - [ ] 1.1.4.4 Show confirmation prompt for spec updates - [ ] 1.1.4.5 Copy specs to main spec directory - [ ] 1.1.5 Implement archive move with date prefixing - [ ] 1.1.6 Support --yes flag to skip confirmations ## 2. CLI Integration - [ ] 2.1 Add archive command to `src/cli/index.ts` - [ ] 2.1.1 Import ArchiveCommand - [ ] 2.1.2 Register command with commander - [ ] 2.1.3 Add --yes/-y flag option - [ ] 2.1.4 Add proper error handling ## 3. Error Handling - [ ] 3.1 Handle missing openspec/changes/ directory - [ ] 3.2 Handle change not found - [ ] 3.3 Handle archive target already exists - [ ] 3.4 Handle user cancellation ## 4. Testing - [ ] 4.1 Test with fully completed change - [ ] 4.2 Test with incomplete tasks (warning shown) - [ ] 4.3 Test interactive selection mode - [ ] 4.4 Test duplicate archive prevention - [ ] 4.5 Test spec update functionality - [ ] 4.5.1 Test creating new specs - [ ] 4.5.2 Test updating existing specs - [ ] 4.5.3 Test confirmation prompt display - [ ] 4.5.4 Test declining confirmation (no changes made) - [ ] 4.5.5 Test --yes flag skips confirmation ## 5. Build and Validation - [ ] 5.1 Ensure TypeScript compilation succeeds - [ ] 5.2 Test command execution ================================================ FILE: openspec/changes/archive/2025-08-13-add-diff-command/proposal.md ================================================ # Add Diff Command to OpenSpec CLI ## Why Developers need to easily view differences between proposed spec changes and current specs without manually comparing files. ## What Changes - Add `openspec diff [change-name]` command that shows differences between change specs and current specs - Compare files in `changes/[change-name]/specs/` with corresponding files in `specs/` - Display unified diff output showing added/removed/modified lines - Support colored output for better readability ## Impact - Affected specs: New capability `cli-diff` will be added - Affected code: - `src/cli/index.ts` - Add diff command - `src/core/diff.ts` - New file with diff logic (~80 lines) ================================================ FILE: openspec/changes/archive/2025-08-13-add-diff-command/specs/cli-diff/spec.md ================================================ # CLI Diff Command Specification ## Purpose The `openspec diff` command provides developers with a visual comparison between proposed spec changes and the current deployed specs. ## Command Syntax ```bash openspec diff [change-name] ``` ## Behavior ### Without Arguments WHEN running `openspec diff` without arguments THEN list all available changes in the `changes/` directory (excluding archive) AND prompt user to select a change ### With Change Name WHEN running `openspec diff ` THEN compare all spec files in `changes//specs/` with corresponding files in `specs/` ### Diff Output FOR each spec file in the change: - IF file exists in both locations THEN show unified diff - IF file only exists in change THEN show as new file (all lines with +) - IF file only exists in current specs THEN show as deleted (all lines with -) ### Display Format The diff SHALL use standard unified diff format: - Lines prefixed with `-` for removed content - Lines prefixed with `+` for added content - Lines without prefix for unchanged context - File headers showing the paths being compared ### Color Support WHEN terminal supports colors: - Removed lines displayed in red - Added lines displayed in green - File headers displayed in bold - Context lines in default color ### Error Handling WHEN specified change doesn't exist THEN display error "Change '' not found" WHEN no specs directory in change THEN display "No spec changes found for ''" WHEN changes directory doesn't exist THEN display "No OpenSpec changes directory found" ## Examples ```bash # View diff for specific change $ openspec diff add-auth-feature --- specs/user-auth/spec.md +++ changes/add-auth-feature/specs/user-auth/spec.md @@ -10,6 +10,8 @@ Users SHALL authenticate with email and password. +Users MAY authenticate with OAuth providers. + WHEN credentials are valid THEN issue JWT token. # List all changes and select $ openspec diff Available changes: 1. add-auth-feature 2. update-payment-flow 3. add-status-command Select a change (1-3): ``` ================================================ FILE: openspec/changes/archive/2025-08-13-add-diff-command/tasks.md ================================================ # Implementation Tasks ## 1. Core Implementation - [x] 1.1 Create `src/core/diff.ts` with diff logic - [x] 1.2 Implement change directory scanning - [x] 1.3 Implement file comparison using unified diff format - [x] 1.4 Add color support for terminal output ## 2. CLI Integration - [x] 2.1 Add diff command to `src/cli/index.ts` - [x] 2.2 Implement interactive change selection when no argument provided - [x] 2.3 Add error handling for missing changes ## 3. Enhancements - [x] 3.1 Replace with jest-diff for professional diff output - [x] 3.2 Improve file headers with status and statistics - [x] 3.3 Add summary view with file counts and line changes ## 4. Testing - [ ] 4.1 Test diff generation for modified files - [ ] 4.2 Test handling of new files - [ ] 4.3 Test handling of deleted files - [ ] 4.4 Test interactive mode ================================================ FILE: openspec/changes/archive/2025-08-19-add-change-commands/design.md ================================================ # Design: Change Commands ## Architecture Decisions ### Command Structure Similar to spec commands, we use subcommands (`change show`, `change list`, `change validate`) for: - Consistency with spec command pattern - Clear separation of concerns - Future extensibility for change management features ### JSON Schema for Changes ```typescript { version: string, // Schema version format: "change", // Identifies as change document sourcePath: string, // Original markdown file path id: string, // Change identifier title: string, // Change title why: string, // Motivation section whatChanges: Array<{ type: "ADDED" | "MODIFIED" | "REMOVED" | "RENAMED", deltas: Array<{ specId: string, description: string, requirements?: Array // Only for ADDED/MODIFIED }> }> } ``` **Rationale:** - Group deltas by operation type for clearer organization - Optional requirements field (only relevant for ADDED/MODIFIED) - Reuse RequirementSchema from spec commands for consistency ### Delta Operations **Four operation types:** 1. **ADDED**: New requirements added to specs 2. **MODIFIED**: Changes to existing requirements 3. **REMOVED**: Requirements being deleted 4. **RENAMED**: Spec identifier changes **Design choice:** Explicit operation types rather than diff-based approach for: - Human readability in markdown - Clear intent communication - Easier validation and tooling ### Dependency on Spec Commands - **Shared schemas**: RequirementSchema and ScenarioSchema reused - **Implementation order**: spec commands must be implemented first - **Common parser utilities**: Share markdown parsing logic ### Legacy Compatibility - Keep existing `list` command functional with deprecation warning - Migration path: `list` → `change list` with same functionality - Gradual transition to avoid breaking existing workflows ================================================ FILE: openspec/changes/archive/2025-08-19-add-change-commands/proposal.md ================================================ # Change: Add Change Commands with JSON Output ## Why OpenSpec change proposals currently can only be viewed as markdown files, creating the same programmatic access limitations as specs. Additionally, the current `openspec list` command only lists changes, which is inconsistent with the new resource-based command structure. ## What Changes - **cli-change:** Add new command for managing change proposals with show, list, and validate subcommands - **cli-list:** Add deprecation notice for legacy list command to guide users to the new change list command ## Impact - **Affected specs**: cli-list (modify to add deprecation notice) - **Affected code**: - src/cli/index.ts (register new command) - src/core/list.ts (add deprecation notice) ================================================ FILE: openspec/changes/archive/2025-08-19-add-change-commands/specs/cli-change/spec.md ================================================ ## ADDED Requirements ### Requirement: Change Command The system SHALL provide a `change` command with subcommands for displaying, listing, and validating change proposals. #### Scenario: Show change as JSON - **WHEN** executing `openspec change show update-error --json` - **THEN** parse the markdown change file - **AND** extract change structure and deltas - **AND** output valid JSON to stdout #### Scenario: List all changes - **WHEN** executing `openspec change list` - **THEN** scan the openspec/changes directory - **AND** return list of all pending changes - **AND** support JSON output with `--json` flag #### Scenario: Show only requirement changes - **WHEN** executing `openspec change show update-error --requirements-only` - **THEN** display only the requirement changes (ADDED/MODIFIED/REMOVED/RENAMED) - **AND** exclude why and what changes sections #### Scenario: Validate change structure - **WHEN** executing `openspec change validate update-error` - **THEN** parse the change file - **AND** validate against Zod schema - **AND** ensure deltas are well-formed ### Requirement: Legacy Compatibility The system SHALL maintain backward compatibility with the existing `list` command while showing deprecation notices. #### Scenario: Legacy list command - **WHEN** executing `openspec list` - **THEN** display current list of changes (existing behavior) - **AND** show deprecation notice: "Note: 'openspec list' is deprecated. Use 'openspec change list' instead." #### Scenario: Legacy list with --all flag - **WHEN** executing `openspec list --all` - **THEN** display all changes (existing behavior) - **AND** show same deprecation notice ================================================ FILE: openspec/changes/archive/2025-08-19-add-change-commands/specs/cli-list/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Command Execution The current `list` command behavior SHALL be preserved but marked as deprecated. #### Scenario: Deprecation notice - **WHEN** using the legacy `list` command - **THEN** continue to work as before - **AND** display deprecation notice - **AND** suggest using `openspec change list` instead ================================================ FILE: openspec/changes/archive/2025-08-19-add-change-commands/tasks.md ================================================ # Implementation Tasks (Phase 2: Builds on add-zod-validation) ## 1. Command Implementation - [x] 1.1 Create src/commands/change.ts - [x] 1.2 Import ChangeSchema and DeltaSchema from src/core/schemas/change.schema.ts - [x] 1.3 Import markdown parser from src/core/parsers/markdown-parser.ts - [x] 1.4 Import ChangeValidator from src/core/validation/validator.ts - [x] 1.5 Import JSON converter from src/core/converters/json-converter.ts - [x] 1.6 Implement show subcommand with JSON output using existing converter - [x] 1.7 Implement list subcommand - [x] 1.8 Implement validate subcommand using existing ChangeValidator - [x] 1.9 Add --requirements-only filtering option - [x] 1.10 Add --strict mode support (leveraging existing validation infrastructure) - [x] 1.11 Add --json flag for validation reports ## 2. Change-Specific Parser Extensions - [x] 2.1 Create src/core/parsers/change-parser.ts (extends base markdown parser) - [x] 2.2 Parse proposal structure (Why, What Changes sections) - [x] 2.3 Extract ADDED/MODIFIED/REMOVED/RENAMED sections - [x] 2.4 Parse delta operations within each section - [x] 2.5 Add tests for change parser ## 3. Legacy Compatibility - [x] 3.1 Update src/core/list.ts to add deprecation notice - [x] 3.2 Ensure existing list command continues to work - [x] 3.3 Add console warning for deprecated command usage ## 4. Integration - [x] 4.1 Register change command in src/cli/index.ts - [ ] 4.2 Add integration tests for all subcommands - [x] 4.3 Test JSON output for changes - [x] 4.4 Test legacy compatibility - [x] 4.5 Test validation with strict mode - [x] 4.6 Update CLI help documentation (add 'change' command to main help, document subcommands: show, list, validate) ================================================ FILE: openspec/changes/archive/2025-08-19-add-interactive-show-command/proposal.md ================================================ ## Why Users frequently need to view changes and specs but must know in advance whether they're looking at a change or spec. The current subcommand structure (`change show`, `spec show`) creates friction when: - Users want to quickly view an item without remembering its type - Exploring the codebase requires switching between different show commands - Show commands without arguments return errors instead of helpful guidance ## What Changes - Add new top-level `show` command for displaying changes or specs with intelligent selection - Support direct item display: `openspec show ` with automatic type detection - Interactive selection when no arguments provided - Enhance existing `change show` and `spec show` to support interactive selection (backwards compatibility) - Maintain all existing format options (--json, --deltas-only, --requirements, etc.) ## Impact - New specs to create: cli-show - Specs to enhance: cli-change, cli-spec (for backwards compatibility) - Affected code: src/cli/index.ts, src/commands/show.ts (new), src/commands/spec.ts, src/commands/change.ts ================================================ FILE: openspec/changes/archive/2025-08-19-add-interactive-show-command/specs/cli-change/spec.md ================================================ # CLI Change Command Spec ## ADDED Requirements ### Requirement: Interactive show selection The change show command SHALL support interactive selection when no change name is provided. #### Scenario: Interactive change selection for show - **WHEN** executing `openspec change show` without arguments - **THEN** display an interactive list of available changes - **AND** allow the user to select a change to show - **AND** display the selected change content - **AND** maintain all existing show options (--json, --deltas-only) #### Scenario: Non-interactive fallback keeps current behavior - **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0` - **WHEN** executing `openspec change show` without a change name - **THEN** do not prompt interactively - **AND** print the existing hint including available change IDs - **AND** set `process.exitCode = 1` ================================================ FILE: openspec/changes/archive/2025-08-19-add-interactive-show-command/specs/cli-show/spec.md ================================================ # CLI Show Command Spec ## ADDED Requirements ### Requirement: Top-level show command The CLI SHALL provide a top-level `show` command for displaying changes and specs with intelligent selection. #### Scenario: Interactive show selection - **WHEN** executing `openspec show` without arguments - **THEN** prompt user to select type (change or spec) - **AND** display list of available items for selected type - **AND** show the selected item's content #### Scenario: Non-interactive environments do not prompt - **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0` - **WHEN** executing `openspec show` without arguments - **THEN** do not prompt - **AND** print a helpful hint with examples for `openspec show ` or `openspec change/spec show` - **AND** exit with code 1 #### Scenario: Direct item display - **WHEN** executing `openspec show ` - **THEN** automatically detect if item is a change or spec - **AND** display the item's content - **AND** use appropriate formatting based on item type #### Scenario: Type detection and ambiguity handling - **WHEN** executing `openspec show ` - **THEN** if `` uniquely matches a change or a spec, show that item - **AND** if it matches both, print an ambiguity error and suggest `--type change|spec` or using `openspec change show`/`openspec spec show` - **AND** if it matches neither, print not-found with nearest-match suggestions #### Scenario: Explicit type override - **WHEN** executing `openspec show --type change ` - **THEN** treat `` as a change ID and show it (skipping auto-detection) - **WHEN** executing `openspec show --type spec ` - **THEN** treat `` as a spec ID and show it (skipping auto-detection) ### Requirement: Output format options The show command SHALL support various output formats consistent with existing commands. #### Scenario: JSON output - **WHEN** executing `openspec show --json` - **THEN** output the item in JSON format - **AND** include parsed metadata and structure - **AND** maintain format consistency with existing change/spec show commands #### Scenario: Flag scoping and delegation - **WHEN** showing a change or a spec via the top-level command - **THEN** accept common flags such as `--json` - **AND** pass through type-specific flags to the corresponding implementation - Change-only flags: `--deltas-only` (alias `--requirements-only` deprecated) - Spec-only flags: `--requirements`, `--no-scenarios`, `-r/--requirement` - **AND** ignore irrelevant flags for the detected type with a warning ### Requirement: Interactivity controls - The CLI SHALL respect `--no-interactive` to disable prompts. - The CLI SHALL respect `OPEN_SPEC_INTERACTIVE=0` to disable prompts globally. - Interactive prompts SHALL only be shown when stdin is a TTY and interactivity is not disabled. #### Scenario: Change-specific options - **WHEN** showing a change with `openspec show --deltas-only` - **THEN** display only the deltas in JSON format - **AND** maintain compatibility with existing change show options #### Scenario: Spec-specific options - **WHEN** showing a spec with `openspec show --requirements` - **THEN** display only requirements in JSON format - **AND** support other spec options (--no-scenarios, -r) - **AND** maintain compatibility with existing spec show options ================================================ FILE: openspec/changes/archive/2025-08-19-add-interactive-show-command/specs/cli-spec/spec.md ================================================ # CLI Spec Command Spec ## ADDED Requirements ### Requirement: Interactive spec show The spec show command SHALL support interactive selection when no spec-id is provided. #### Scenario: Interactive spec selection for show - **WHEN** executing `openspec spec show` without arguments - **THEN** display an interactive list of available specs - **AND** allow the user to select a spec to show - **AND** display the selected spec content - **AND** maintain all existing show options (--json, --requirements, --no-scenarios, -r) #### Scenario: Non-interactive fallback keeps current behavior - **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0` - **WHEN** executing `openspec spec show` without a spec-id - **THEN** do not prompt interactively - **AND** print the existing error message for missing spec-id - **AND** set non-zero exit code ================================================ FILE: openspec/changes/archive/2025-08-19-add-interactive-show-command/tasks.md ================================================ # Implementation Tasks — Add Interactive Show Command ## Goals - Add a top-level `show` command with intelligent selection and type detection. - Add interactive selection to `change show` and `spec show` when no ID is provided. - Preserve raw-first output behavior and existing JSON formats/filters. - Respect `--no-interactive` and `OPEN_SPEC_INTERACTIVE=0` consistently. --- ## 1) CLI wiring - [x] In `src/cli/index.ts` add a top-level command: `program.command('show [item-name]')` - Options: - `--json` - `--type ` where `` is `change|spec` - `--no-interactive` - Allow passing-through type-specific flags using `.allowUnknownOption(true)` so the top-level can forward flags to the underlying type handler. - Action: instantiate `new ShowCommand().execute(itemName, options)`. - [x] Update `change show` subcommand to accept `--no-interactive` and pass it to `ChangeCommand.show(...)`. - [x] Change `spec show` subcommand to accept optional ID (`show [spec-id]`), add `--no-interactive`, and pass to spec show implementation. Acceptance: - `openspec show` exists and prints a helpful hint in non-interactive contexts when no args. - Unknown flags for other types do not crash parsing; they are warned/ignored appropriately. --- ## 2) New module: `src/commands/show.ts` - [x] Create `ShowCommand` with: - `execute(itemName?: string, options?: { json?: boolean; type?: string; noInteractive?: boolean; [k: string]: any })` - Interactive path when `!itemName` and interactive is enabled: - Prompt: "What would you like to show?" → `change` or `spec`. - Load available IDs for the chosen type and prompt selection. - Delegate to type-specific show implementation. - Non-interactive path when `!itemName`: - Print hint with examples: - `openspec show ` - `openspec change show` - `openspec spec show` - Exit with code 1. - Direct item path when `itemName` is provided: - Type override via `--type` takes precedence. - Otherwise detect using `getActiveChangeIds()` and `getSpecIds()`. - If ambiguous and no override: print error + suggestion to pass `--type` or use subcommands; exit code 1. - If unknown: print not-found with nearest-match suggestions; exit code 1. - On success: delegate to type-specific show. - [x] Flag scoping and pass-through: - Common: `--json` → forwarded to both types. - Change-only: `--deltas-only`, `--requirements-only` (deprecated alias). - Spec-only: `--requirements`, `--no-scenarios`, `-r/--requirement`. - Warn and ignore irrelevant flags for the resolved type. Acceptance: - `openspec show --json --deltas-only` matches `openspec change show --json --deltas-only` output. - `openspec show --json --requirements` matches `openspec spec show --json --requirements` output. - Ambiguity and not-found behaviors match the `cli-show` spec. --- ## 3) Refactor spec show into reusable API - [x] In `src/commands/spec.ts`, extract show logic into an exported `SpecCommand` with `show(specId?: string, options?: { json?: boolean; requirements?: boolean; scenarios?: boolean; requirement?: string; noInteractive?: boolean })`. - Reuse current helpers (`parseSpecFromFile`, `filterSpec`, raw-first printing). - Keep `registerSpecCommand` but delegate to `new SpecCommand().show(...)`. - [x] Update CLI spec show subcommand to optional arg and interactive behavior (see section 4). Acceptance: - Existing `spec show` tests continue to pass. - New `SpecCommand.show` can be called from `ShowCommand`. --- ## 4) Backwards-compatible interactive in subcommands - [x] `src/commands/change.ts` → extend `show(changeName?: string, options?: { json?: boolean; requirementsOnly?: boolean; deltasOnly?: boolean; noInteractive?: boolean })`: - When `!changeName` and interactive enabled: prompt from `getActiveChangeIds()` and show the selected change. - Non-interactive fallback: keep current behavior (print available IDs + `openspec change list` hint, set `process.exitCode = 1`). - [x] `src/commands/spec.ts` → `SpecCommand.show` as above: - When `!specId` and interactive enabled: prompt from `getSpecIds()` and show the selected spec. - Non-interactive fallback: print the same error as existing behavior for missing `` and set non-zero exit code. Acceptance: - `openspec change show` in non-interactive prints list hint and exits non-zero. - `openspec spec show` in non-interactive prints missing-arg error and exits non-zero. --- ## 5) Shared utilities - [x] Extract `nearestMatches` and `levenshtein` from `src/commands/validate.ts` into `src/utils/match.ts` (exported helpers). - [x] Update `ValidateCommand` and new `ShowCommand` to import from `utils/match`. Acceptance: - Build succeeds with shared helpers and no duplication. --- ## 6) Hints, warnings, and messages - [x] Top-level `show` hint (non-interactive no-arg): - Lines include: `openspec show `, `openspec change show`, `openspec spec show`, and "Or run in an interactive terminal.". - [x] Ambiguity message suggests `--type change|spec` and the subcommands. - [x] Not-found suggests nearest matches (up to 5). - [x] Irrelevant flag warnings for the resolved type (printed to stderr, no crash). Acceptance: - Messages match the `cli-show` spec wording intent and style used elsewhere. --- ## 7) Tests Add tests mirroring existing patterns (non-TTY simulation via `OPEN_SPEC_INTERACTIVE=0`). - [x] `test/commands/show.test.ts` - Non-interactive, no arg → prints hint and exits non-zero. - Direct item detection for change and for spec. - Ambiguity case when both exist → error and suggestion for `--type`. - Not-found case → nearest-match suggestions. - Pass-through flags: change `--json --deltas-only`, spec `--json --requirements`. - [x] `test/commands/change.interactive-show.test.ts` (non-interactive fallback) - Ensure `openspec change show` without args prints available IDs + list hint and non-zero exit. - [x] `test/commands/spec.interactive-show.test.ts` (non-interactive fallback) - Ensure `openspec spec show` without args prints missing-arg error and non-zero exit. Acceptance: - All new tests pass after build; no regressions in existing tests. --- ## 8) Documentation (optional but recommended) - [x] Update `openspec/README.md` usage examples to include the new `show` command with type detection and flags. --- ## 9) Non-functional checks - [x] Run `pnpm build` and all tests (`pnpm test`). - [x] Ensure no linter/type errors and messages are consistent with existing style. --- ## Notes on consistency - Follow raw-first behavior for text output: passthrough file content with no formatting, mirroring current `change show` and `spec show`. - Reuse `isInteractive` and `item-discovery` helpers for consistent prompting behavior. - Keep JSON output shapes identical to current `ChangeCommand.show` and `spec show` outputs. ================================================ FILE: openspec/changes/archive/2025-08-19-add-skip-specs-archive-option/proposal.md ================================================ ## Why The archive command currently forces users to either accept spec updates or cancel the entire archive operation. Users need flexibility to archive changes without updating specs, either through explicit flags or by declining the confirmation prompt. This is especially important for changes that don't modify specs (like tooling, documentation, or infrastructure updates). ## What Changes - Add new `--skip-specs` flag to the archive command that bypasses all spec update operations - Fix confirmation behavior: when users decline spec updates interactively, proceed with archiving instead of cancelling the entire operation - When `--skip-specs` flag is used, skip both the spec discovery and update confirmation steps entirely - Display clear message when specs are skipped (either via flag or user choice) - Flag can be combined with existing `--yes` flag for fully automated archiving without spec updates ## Impact - Affected specs: cli-archive - Affected code: src/core/archive.ts, src/cli/index.ts ================================================ FILE: openspec/changes/archive/2025-08-19-add-skip-specs-archive-option/specs/cli-archive/spec.md ================================================ # CLI Archive Command Specification ## Purpose The archive command moves completed changes from the active changes directory to the archive folder with date-based naming, following OpenSpec conventions. ## Command Syntax ```bash openspec archive [change-name] [--yes|-y] [--skip-specs] ``` Options: - `--yes`, `-y`: Skip confirmation prompts (for automation) - `--skip-specs`: Skip spec update operations entirely (for changes without spec modifications) ## Behavior ### Requirement: Change Selection The command SHALL support both interactive and direct change selection methods. #### Scenario: Interactive selection - **WHEN** no change-name is provided - **THEN** display interactive list of available changes (excluding archive/) - **AND** allow user to select one #### Scenario: Direct selection - **WHEN** change-name is provided - **THEN** use that change directly - **AND** validate it exists ### Requirement: Task Completion Check The command SHALL verify task completion status before archiving to prevent premature archival. #### Scenario: Incomplete tasks found - **WHEN** incomplete tasks are found (marked with `- [ ]`) - **THEN** display all incomplete tasks to the user - **AND** prompt for confirmation to continue - **AND** default to "No" for safety #### Scenario: All tasks complete - **WHEN** all tasks are complete OR no tasks.md exists - **THEN** proceed with archiving without prompting ### Requirement: Archive Process The archive operation SHALL follow a structured process to safely move changes to the archive. #### Scenario: Performing archive - **WHEN** archiving a change - **THEN** execute these steps: 1. Create archive/ directory if it doesn't exist 2. Generate target name as `YYYY-MM-DD-[change-name]` using current date 3. Check if target directory already exists 4. Update main specs from the change's future state specs unless `--skip-specs` is provided (see Spec Update Process below) 5. Move the entire change directory to the archive location #### Scenario: Archive already exists - **WHEN** target archive already exists - **THEN** fail with error message - **AND** do not overwrite existing archive #### Scenario: Successful archive - **WHEN** move succeeds - **THEN** display success message with archived name and list of updated specs (if any) ### Requirement: Spec Update Process Before moving the change to archive, the command SHALL update main specs to reflect the deployed reality unless the `--skip-specs` flag is provided. #### Scenario: Skipping spec updates - **WHEN** the `--skip-specs` flag is provided - **THEN** skip all spec discovery and update operations - **AND** proceed directly to moving the change to archive - **AND** display message indicating specs were skipped #### Scenario: Updating specs from change - **WHEN** the change contains specs in `changes/[name]/specs/` AND `--skip-specs` is NOT provided - **THEN** execute these steps: 1. Analyze which specs will be affected by comparing with existing specs 2. Display a summary of spec updates to the user (see Confirmation Behavior below) 3. Prompt for confirmation unless `--yes` flag is provided 4. If confirmed, for each capability spec in the change directory: - Copy the spec from `changes/[name]/specs/[capability]/spec.md` to `openspec/specs/[capability]/spec.md` - Create the target directory structure if it doesn't exist - Overwrite existing spec files (specs represent current reality, change specs are the new reality) - Track which specs were updated for the success message #### Scenario: No specs in change - **WHEN** no specs exist in the change AND `--skip-specs` is NOT provided - **THEN** skip the spec update step - **AND** proceed with archiving ### Requirement: Confirmation Behavior The spec update confirmation SHALL provide clear visibility into changes before they are applied. #### Scenario: Displaying confirmation - **WHEN** prompting for confirmation AND `--skip-specs` is NOT provided - **THEN** display a clear summary showing: - Which specs will be created (new capabilities) - Which specs will be updated (existing capabilities) - The source path for each spec - **AND** format the confirmation prompt as: ``` The following specs will be updated: NEW specs to be created: - cli-archive (from changes/add-archive-command/specs/cli-archive/spec.md) EXISTING specs to be updated: - cli-init (from changes/update-init-command/specs/cli-init/spec.md) Update 2 specs and archive 'add-archive-command'? [y/N]: ``` #### Scenario: Handling confirmation response - **WHEN** waiting for user confirmation - **THEN** default to "No" for safety (require explicit "y" or "yes") - **AND** skip confirmation when `--yes` or `-y` flag is provided - **AND** skip entire spec confirmation when `--skip-specs` flag is provided #### Scenario: User declines spec update confirmation - **WHEN** user declines the spec update confirmation - **THEN** skip the spec update operations - **AND** display message: "Skipping spec updates. Proceeding with archive." - **AND** continue with the archive operation - **AND** display success message indicating specs were not updated ## Error Handling ### Requirement: Error Conditions The command SHALL handle various error conditions gracefully. #### Scenario: Handling errors - **WHEN** errors occur - **THEN** handle the following conditions: - Missing openspec/changes/ directory - Change not found - Archive target already exists - File system permissions issues ## Why These Decisions **Interactive selection**: Reduces typing and helps users see available changes **Task checking**: Prevents accidental archiving of incomplete work **Date prefixing**: Maintains chronological order and prevents naming conflicts **No overwrite**: Preserves historical archives and prevents data loss **Spec updates before archiving**: Specs in the main directory represent current reality; when a change is deployed and archived, its future state specs become the new reality and must replace the main specs **Confirmation for spec updates**: Provides visibility into what will change, prevents accidental overwrites, and ensures users understand the impact before specs are modified **Non-blocking confirmation**: Declining spec updates doesn't cancel archiving - users can review specs and choose to update them separately if needed **--yes flag for automation**: Allows CI/CD pipelines to archive without interactive prompts while maintaining safety by default for manual use **--skip-specs flag**: Enables archiving of changes that don't modify specs (like infrastructure, tooling, or documentation changes) without unnecessary spec update prompts or operations ## ADDED Requirements ### Requirement: Skip Specs Option The archive command SHALL support a `--skip-specs` flag that skips all spec update operations and proceeds directly to archiving. #### Scenario: Skipping spec updates with flag - **WHEN** executing `openspec archive --skip-specs` - **THEN** skip spec discovery and update confirmation - **AND** proceed directly to moving the change to archive - **AND** display a message indicating specs were skipped ### Requirement: Non-blocking confirmation The archive operation SHALL proceed when the user declines spec updates instead of cancelling the entire operation. #### Scenario: User declines spec update confirmation - **WHEN** the user declines spec update confirmation - **THEN** skip spec updates - **AND** continue with the archive operation - **AND** display a success message indicating specs were not updated ================================================ FILE: openspec/changes/archive/2025-08-19-add-skip-specs-archive-option/tasks.md ================================================ ## 1. Update Archive Command Implementation - [x] 1.1 Add `skipSpecs` option to the archive command options interface - [x] 1.2 Modify the execute method to skip spec operations when flag is set - [x] 1.3 Fix confirmation behavior: when user declines spec updates, proceed with archiving instead of cancelling - [x] 1.4 Update console output to indicate when specs are being skipped (via flag or user choice) - [x] 1.5 Ensure archive continues after declining spec updates ## 2. Update CLI Interface - [x] 2.1 Add `--skip-specs` flag to the archive command definition - [x] 2.2 Pass the flag value to the archive command execute method ## 3. Update Tests - [x] 3.1 Add test case for archiving with --skip-specs flag - [x] 3.2 Add test case for declining spec updates but continuing with archive - [x] 3.3 Verify that spec updates are skipped when flag is used - [x] 3.4 Verify that archive proceeds when user declines spec updates - [x] 3.5 Ensure existing behavior remains unchanged when flag is not used ## 4. Update Documentation - [x] 4.1 Update the cli-archive spec to document the new --skip-specs flag - [x] 4.2 Document the new behavior when declining spec updates interactively ## Implementation Notes ### Key Design Decisions 1. **Non-blocking Confirmation Behavior**: When users decline spec updates interactively, the archive operation continues rather than cancelling entirely. This was a critical UX improvement because: - Users may want to review specs separately before updating them - Archiving work shouldn't be blocked by spec review decisions - Maintains flexibility in the deployment workflow 2. **Flag Naming Convention**: Chose `--skip-specs` for clarity and consistency: - Clearly indicates the action (skipping) and target (specs) - Follows kebab-case convention for CLI flags - Converts naturally to `skipSpecs` camelCase in code 3. **Console Messaging Strategy**: Added explicit messages for all spec-skipping scenarios: - When flag is used: "Skipping spec updates (--skip-specs flag provided)." - When user declines: "Skipping spec updates. Proceeding with archive." - Ensures users always understand what's happening with their specs 4. **Test Coverage Approach**: Created separate test cases for: - Flag-based skipping (explicit user choice via CLI) - Interactive declining (runtime user decision) - Both verify the same outcome but test different code paths ### Use Cases Addressed - **Infrastructure Changes**: Changes to build tools, CI/CD, dependencies - **Documentation Updates**: README updates, comment improvements - **Tooling Modifications**: Developer tools, scripts, configuration files - **Refactoring**: Code improvements that don't change functionality/specs ### Future Considerations - Could potentially auto-detect when changes don't include specs and suggest using the flag - May want to track which archives skipped spec updates for audit purposes ================================================ FILE: openspec/changes/archive/2025-08-19-add-spec-commands/design.md ================================================ # Design: Spec Commands ## Architecture Decisions ### Command Hierarchy We chose a subcommand pattern (`spec show`, `spec list`, `spec validate`) to: - Group related functionality under a common namespace - Enable future extensibility without polluting the top-level CLI - Maintain consistency with the planned `change` command structure ### JSON Schema Structure The spec JSON schema follows this structure: ```typescript { version: string, // Schema version for compatibility format: "spec", // Identifies this as a spec document sourcePath: string, // Original markdown file path id: string, // Spec identifier from filename title: string, // Human-readable title overview?: string, // Optional overview section requirements: Array<{ id: string, text: string, scenarios: Array<{ id: string, text: string }> }> } ``` **Rationale:** - Flat structure for requirements array (vs nested objects) for easier iteration - Scenarios nested within requirements to maintain relationship - Metadata fields (version, format, sourcePath) for tooling integration ### Parser Architecture - **Markdown-first approach**: Parse markdown headings rather than custom syntax - **Streaming parser**: Process line-by-line to handle large files efficiently - **Strict heading hierarchy**: Enforce ##/###/#### structure for consistency ### Validation Strategy - **Parse-time validation**: Catch structural issues during parsing - **Schema validation**: Use Zod for runtime type checking of parsed data - **Separate validation command**: Allow validation without full parsing/conversion ================================================ FILE: openspec/changes/archive/2025-08-19-add-spec-commands/proposal.md ================================================ # Change: Add Spec Commands with JSON Output ## Why Currently, OpenSpec specs can only be viewed as markdown files. This makes programmatic access difficult and prevents integration with CI/CD pipelines, external tools, and automated processing. ## What Changes - Add new `openspec spec` command with three subcommands: `show`, `list`, and `validate` - Implement JSON output capability for specs using heading-based parsing - Add Zod schemas for spec structure validation - Enable content filtering options (requirements only, no scenarios, specific requirement) ## Impact - **Affected specs**: None (new capability) - **Affected code**: - src/cli/index.ts (register new command) - package.json (add zod dependency) ================================================ FILE: openspec/changes/archive/2025-08-19-add-spec-commands/specs/cli-spec/spec.md ================================================ ## ADDED Requirements ### Requirement: Spec Command The system SHALL provide a `spec` command with subcommands for displaying, listing, and validating specifications. #### Scenario: Show spec as JSON - **WHEN** executing `openspec spec show init --json` - **THEN** parse the markdown spec file - **AND** extract headings and content hierarchically - **AND** output valid JSON to stdout #### Scenario: List all specs - **WHEN** executing `openspec spec list` - **THEN** scan the openspec/specs directory - **AND** return list of all available capabilities - **AND** support JSON output with `--json` flag #### Scenario: Filter spec content - **WHEN** executing `openspec spec show init --requirements` - **THEN** display only requirement names and SHALL statements - **AND** exclude scenario content #### Scenario: Validate spec structure - **WHEN** executing `openspec spec validate init` - **THEN** parse the spec file - **AND** validate against Zod schema - **AND** report any structural issues ### Requirement: JSON Schema Definition The system SHALL define Zod schemas that accurately represent the spec structure for runtime validation. #### Scenario: Schema validation - **WHEN** parsing a spec into JSON - **THEN** validate the structure using Zod schemas - **AND** ensure all required fields are present - **AND** provide clear error messages for validation failures ================================================ FILE: openspec/changes/archive/2025-08-19-add-spec-commands/tasks.md ================================================ # Implementation Tasks (Phase 3: Builds on add-zod-validation and add-change-commands) ## 1. Command Implementation - [x] 1.1 Create src/commands/spec.ts - [x] 1.2 Import RequirementSchema, ScenarioSchema, SpecSchema from src/core/schemas/ - [x] 1.3 Import markdown parser from src/core/parsers/markdown-parser.ts - [x] 1.4 Import SpecValidator from src/core/validation/validator.ts - [x] 1.5 Import JSON converter from src/core/converters/json-converter.ts - [x] 1.6 Implement show subcommand with JSON output using existing converter - [x] 1.7 Implement list subcommand - [x] 1.8 Implement validate subcommand using existing SpecValidator - [x] 1.9 Add filtering options (--requirements, --no-scenarios, -r) - [x] 1.10 Add --strict mode support (leveraging existing validation infrastructure) - [x] 1.11 Add --json flag for validation reports ## 2. Integration - [x] 2.1 Register spec command in src/cli/index.ts - [x] 2.2 Add integration tests for all subcommands - [x] 2.3 Test JSON output validation - [x] 2.4 Test filtering options - [x] 2.5 Test validation with strict mode - [x] 2.6 Update CLI help documentation (add 'spec' command to main help, document subcommands: show, list, validate) ================================================ FILE: openspec/changes/archive/2025-08-19-add-zod-validation/design.md ================================================ # Design: Zod Validation Framework ## Architecture Decisions ### Validation Levels Three-tier validation system: 1. **ERROR**: Structural issues that prevent parsing (must fix) 2. **WARNING**: Quality issues that should be addressed (recommended fix) 3. **INFO**: Suggestions for improvement (optional) **Rationale:** - Gradual enforcement allows teams to adopt validation incrementally - CI/CD can fail on errors but allow warnings initially - Info level provides guidance without blocking ### Validation Rules Hierarchy #### Spec Validation Rules ``` ERROR level: - Missing ## Overview or ## Requirements sections - Invalid heading hierarchy - Malformed requirement/scenario structure WARNING level: - Requirements without scenarios - Requirements missing SHALL keyword - Empty overview section INFO level: - Very long requirement text (>500 chars) - Scenarios without Given/When/Then structure ``` #### Change Validation Rules ``` ERROR level: - Missing ## Why or ## What Changes sections - Invalid delta operation types - Malformed delta structure WARNING level: - Why section too brief (<50 chars) - Deltas without clear descriptions - Missing requirements in ADDED/MODIFIED INFO level: - Very long why section (>1000 chars) - Too many deltas in single change (>10) ``` ### Strict Mode - **Default**: Show all levels, fail on ERROR only - **--strict flag**: Fail on both ERROR and WARNING - **Use case**: Gradual quality improvement in CI/CD pipelines ### Archive Command Safety **Problem:** Invalid specs could be archived, polluting the archive. **Solution:** 1. Pre-archive validation (default behavior) 2. --no-validate flag with safeguards: - Interactive confirmation prompt - Prominent warning message - Console logging with timestamp - Not recommended for CI/CD usage **Rationale:** - Protect archive integrity by default - Allow emergency overrides with accountability - Clear audit trail for validation bypasses ### Validation Report Format ```json { "valid": boolean, "issues": [ { "level": "ERROR" | "WARNING" | "INFO", "path": "requirements[0].scenarios", "message": "Requirement must have at least one scenario", "line": 15, "column": 0 } ], "summary": { "errors": 2, "warnings": 5, "info": 3 } } ``` **Benefits:** - Machine-readable for tooling integration - Human-friendly messages - Line/column info for IDE integration - Summary for quick assessment ### Implementation Strategy 1. **Zod schemas with refinements**: Built-in validation in type definitions 2. **Custom validators**: Additional business logic validation 3. **Composable rules**: Mix and match for different contexts 4. **Extensible framework**: Easy to add new rules without refactoring ================================================ FILE: openspec/changes/archive/2025-08-19-add-zod-validation/proposal.md ================================================ # Change: Add Zod Runtime Validation ## Why While the spec and change commands can output JSON, they currently don't perform strict runtime validation beyond basic structure checking. This can lead to invalid specs or changes being processed, silent failures when required fields are missing, and poor error messages. ## What Changes - Enhance existing `spec validate` and `change validate` commands with strict Zod validation - Add validation to the archive command to ensure changes are valid before applying - Add validation to the diff command to ensure changes are well-formed - Provide detailed validation reports in JSON format - Add `--strict` mode that fails on warnings ## Impact - **Affected specs**: cli-spec, cli-change, cli-archive, cli-diff - **Affected code**: - src/commands/spec.ts (enhance validate subcommand) - src/commands/change.ts (enhance validate subcommand) - src/core/archive.ts (add pre-archive validation) - src/core/diff.ts (add validation check) ================================================ FILE: openspec/changes/archive/2025-08-19-add-zod-validation/specs/cli-archive/spec.md ================================================ ## ADDED Requirements ### Requirement: Archive Validation The archive command SHALL validate changes before applying them to ensure data integrity. #### Scenario: Pre-archive validation - **WHEN** executing `openspec archive change-name` - **THEN** validate the change structure first - **AND** only proceed if validation passes - **AND** show validation errors if it fails #### Scenario: Force archive without validation - **WHEN** executing `openspec archive change-name --no-validate` - **THEN** skip validation (unsafe mode) - **AND** show warning about skipping validation ================================================ FILE: openspec/changes/archive/2025-08-19-add-zod-validation/specs/cli-diff/spec.md ================================================ ## ADDED Requirements ### Requirement: Diff Command Enhancement The diff command SHALL validate change structure before displaying differences. #### Scenario: Validate before diff - **WHEN** executing `openspec diff change-name` - **THEN** validate change structure - **AND** show validation warnings if present - **AND** continue with diff display ================================================ FILE: openspec/changes/archive/2025-08-19-add-zod-validation/tasks.md ================================================ # Implementation Tasks (Foundation Phase) ## 1. Core Schemas - [x] 1.1 Add zod dependency to package.json - [x] 1.2 Create src/core/schemas/base.schema.ts with ScenarioSchema and RequirementSchema - [x] 1.3 Create src/core/schemas/spec.schema.ts with SpecSchema - [x] 1.4 Create src/core/schemas/change.schema.ts with DeltaSchema and ChangeSchema - [x] 1.5 Create src/core/schemas/index.ts to export all schemas ## 2. Parser Implementation - [x] 2.1 Create src/core/parsers/markdown-parser.ts - [x] 2.2 Implement heading extraction (##, ###, ####) - [x] 2.3 Implement content capture between headings - [x] 2.4 Add tests for parser edge cases ## 3. Validation Infrastructure - [x] 3.1 Create src/core/validation/types.ts with ValidationLevel, ValidationIssue, ValidationReport types - [x] 3.2 Create src/core/validation/constants.ts with validation rules and thresholds - [x] 3.3 Create src/core/validation/validator.ts with SpecValidator and ChangeValidator classes ## 4. Enhanced Validation Rules - [x] 4.1 Add RequirementValidation refinements (must have scenarios, must contain SHALL) - [x] 4.2 Add SpecValidation refinements (must have requirements) - [x] 4.3 Add ChangeValidation refinements (must have deltas, why section length) - [x] 4.4 Implement custom error messages for each rule ## 5. JSON Converter - [x] 5.1 Create src/core/converters/json-converter.ts - [x] 5.2 Implement spec-to-JSON conversion - [x] 5.3 Implement change-to-JSON conversion - [x] 5.4 Add metadata fields (version, format, sourcePath) ## 6. Archive Command Enhancement - [x] 6.1 Add pre-archive validation check using new validators - [x] 6.2 Add --no-validate flag with required confirmation prompt and warning message: "⚠️ WARNING: Skipping validation may archive invalid specs. Continue? (y/N)" - [x] 6.3 Display validation errors before aborting - [x] 6.4 Log all --no-validate usages to console with timestamp and affected files - [x] 6.5 Add tests for validation scenarios including --no-validate confirmation flow ## 7. Diff Command Enhancement - [x] 7.1 Add validation check before diff using new validators - [x] 7.2 Show validation warnings (non-blocking) - [x] 7.3 Continue with diff even if warnings present ## 8. Testing - [x] 8.1 Unit tests for all schemas - [x] 8.2 Unit tests for parser - [x] 8.3 Unit tests for validation rules - [x] 8.4 Integration tests for validation reports - [x] 8.5 Test various invalid spec/change formats - [x] 8.6 Test strict mode behavior - [x] 8.7 Test pre-archive validation - [x] 8.8 Test validation report JSON output ## 9. Documentation - [x] 9.1 Document schema structure and validation rules (openspec/VALIDATION.md) - [x] 9.2 Update CLI help for archive (document --no-validate flag and its warnings) - [x] 9.3 Update CLI help for diff (document validation warnings behavior) - [x] 9.4 Create migration guide for future command integration (openspec/MIGRATION.md) ================================================ FILE: openspec/changes/archive/2025-08-19-adopt-delta-based-changes/proposal.md ================================================ # Adopt Delta-Based Changes for Specifications ## Why The current approach of storing complete future states in change proposals creates a poor review experience. When reviewing changes on GitHub, reviewers see entire spec files (often 100+ lines) as "added" in green, making it impossible to identify what actually changed. With the recent structured format adoption, we now have clear section boundaries that enable a better approach: storing only additions and modifications. ## What Changes Store only the requirements that actually change, not complete future states: - **ADDED Requirements**: New capabilities being introduced - **MODIFIED Requirements**: Existing requirements being changed (must match current header) - **REMOVED Requirements**: Deprecated capabilities - **RENAMED Requirements**: Explicit header changes (e.g., `FROM: Old Name` → `TO: New Name`) The archive command will programmatically apply these deltas using normalized header matching (trim leading/trailing whitespace) instead of manually copying entire files. ## Impact **Affected specs**: openspec-conventions, cli-archive, cli-diff **Benefits**: - GitHub diffs show only actual changes (25 lines instead of 150+) - Reviewers immediately see what's being added, modified, or removed - Conflicts are more apparent when two changes modify the same requirement - Archive command can programmatically apply changes **Format**: Delta format only - all changes must use ADDED/MODIFIED/REMOVED sections. ## Example Instead of storing a 150-line complete future spec, store only: ```markdown # User Authentication - Changes ## ADDED Requirements ### Requirement: OAuth Support Users SHALL authenticate via OAuth providers including Google and GitHub. #### Scenario: OAuth login flow - **WHEN** user selects OAuth provider - **THEN** redirect to provider authorization - **AND** exchange authorization code for tokens ## MODIFIED Requirements ### Requirement: Session Management Sessions SHALL expire after 30 minutes of inactivity. #### Scenario: Inactive session timeout - **WHEN** no activity for 30 minutes ← (was 60 minutes) - **THEN** invalidate session token - **AND** require re-authentication ## RENAMED Requirements - FROM: `### Requirement: Basic Authentication` - TO: `### Requirement: Email Authentication` ``` This makes reviews focused and changes explicit. ## Conflict Resolution Git naturally detects conflicts when two changes modify the same requirement header. This is actually better than full-state storage where Git might silently merge incompatible changes. ## Decisions and Product Guidelines To keep the archive flow lean and predictable, the following decisions apply: - New spec creation: When a target spec does not exist, auto-generate a minimal skeleton and insert ADDED requirements only. Skeleton format: - `# [Spec Name] Specification` - `## Purpose` with placeholder: "TBD — created by archiving change [change-name]. Update Purpose after archive." - `## Requirements` - If a non-existent spec includes MODIFIED/REMOVED/RENAMED, abort with guidance to create via ADDED-only first. - Requirement identification: Match requirements by exact header `### Requirement: [Name]` with trim-only normalization and case-sensitive comparison. Use a requirement-block extractor that preserves the exact header and captures full content (including scenarios) for both main specs and delta files. - Application order and atomicity: Apply deltas in order RENAMED → REMOVED → MODIFIED → ADDED. Validate all operations first, apply in-memory, and write each spec once. On any validation failure, abort without writing partial results. An aggregated totals line is displayed across all specs: `Totals: + A, ~ M, - R, → N`. - Validation matrix: Enforce that MODIFIED/REMOVED exist; ADDED do not exist; RENAMED FROM exists and TO does not; no duplicates after all operations; and no cross-section conflicts (e.g., same item in MODIFIED and REMOVED). When a rename and modify apply to the same item, MODIFIED must reference the NEW header. - Idempotency: Keep v1 simple. Abort on precondition failures (e.g., ADDED already exists) with clear errors. Do not implement no-op detection in v1. - Output and UX: For each spec, display operation counts using standard symbols `+ ~ - →`. Optionally include a short aggregated totals line at the end. Keep messages concise and actionable. - Error messaging: Standardize messages as `[spec] [operation] failed for header "### Requirement: X" — reason`. On abort, explicitly state: `Aborted. No files were changed.` - Subsections: Any subsections under a requirement (e.g., `#### Scenario: ...`) are preserved verbatim during parsing and application. - Backward compatibility: Reject full future-state spec copies for existing specs with guidance to convert to deltas. Allow brand-new specs to be created via ADDED-only deltas using the skeleton above. - Dry-run: Deferred for v1 to keep scope minimal. ================================================ FILE: openspec/changes/archive/2025-08-19-adopt-delta-based-changes/specs/cli-archive/spec.md ================================================ # CLI Archive Command - Changes ## MODIFIED Requirements ### Requirement: Spec Update Process Before moving the change to archive, the command SHALL apply delta changes to main specs to reflect the deployed reality. #### Scenario: Applying delta changes - **WHEN** archiving a change with delta-based specs - **THEN** parse and apply delta changes as defined in openspec-conventions - **AND** validate all operations before applying #### Scenario: Validating delta changes - **WHEN** processing delta changes - **THEN** perform validations as specified in openspec-conventions - **AND** if validation fails, show specific errors and abort #### Scenario: Conflict detection - **WHEN** applying deltas would create duplicate requirement headers - **THEN** abort with error message showing the conflict - **AND** suggest manual resolution ## ADDED Requirements ### Requirement: Display Output The command SHALL provide clear feedback about delta operations. #### Scenario: Showing delta application - **WHEN** applying delta changes - **THEN** display for each spec: - Number of requirements added - Number of requirements modified - Number of requirements removed - Number of requirements renamed - **AND** use standard output symbols (+ ~ - →) as defined in openspec-conventions: ``` Applying changes to specs/user-auth/spec.md: + 2 added ~ 3 modified - 1 removed → 1 renamed ``` ================================================ FILE: openspec/changes/archive/2025-08-19-adopt-delta-based-changes/specs/cli-diff/spec.md ================================================ # CLI Diff Command - Changes ## REMOVED Requirements ### Requirement: Display Format The diff command SHALL display unified diff output in text format. **Reason for removal**: The standard unified diff format is replaced by requirement-level side-by-side comparison that better shows semantic changes rather than line-by-line text differences. #### Scenario: Unified diff output (deprecated) - **WHEN** running `openspec diff ` - **THEN** show a unified text diff of files - **AND** include `+`/`-` prefixed lines representing additions and removals ## MODIFIED Requirements ### Requirement: Diff Output The command SHALL show a requirement-level comparison displaying only changed requirements. #### Scenario: Side-by-side comparison of changes - **WHEN** running `openspec diff ` - **THEN** display only requirements that have changed - **AND** show them in a side-by-side format that: - Clearly shows the current version on the left - Shows the future version on the right - Indicates new requirements (not in current) - Indicates removed requirements (not in future) - Aligns modified requirements for easy comparison ## ADDED Requirements ### Requirement: Validation The command SHALL validate that changes can be applied successfully. #### Scenario: Invalid delta references - **WHEN** delta references non-existent requirement - **THEN** show error message with specific requirement - **AND** continue showing other valid changes - **AND** clearly mark failed changes in the output ================================================ FILE: openspec/changes/archive/2025-08-19-adopt-delta-based-changes/specs/openspec-conventions/spec.md ================================================ # OpenSpec Conventions - Changes ## MODIFIED Requirements ### Requirement: Header-Based Requirement Identification Requirement headers SHALL serve as unique identifiers for programmatic matching between current specs and proposed changes. #### Scenario: Matching requirements programmatically - **WHEN** processing delta changes - **THEN** use the `### Requirement: [Name]` header as the unique identifier - **AND** match using normalized headers: `normalize(header) = trim(header)` - **AND** compare headers with case-sensitive equality after normalization #### Scenario: Handling requirement renames - **WHEN** renaming a requirement - **THEN** use a special `## RENAMED Requirements` section - **AND** specify both old and new names explicitly: ```markdown ## RENAMED Requirements - FROM: `### Requirement: Old Name` - TO: `### Requirement: New Name` ``` - **AND** if content also changes, include under MODIFIED using the NEW header #### Scenario: Validating header uniqueness - **WHEN** creating or modifying requirements - **THEN** ensure no duplicate headers exist within a spec - **AND** validation tools SHALL flag duplicate headers as errors ### Requirement: Change Storage Convention Change proposals SHALL store only the additions, modifications, and removals to specifications, not complete future states. #### Scenario: Creating change proposals with additions - **WHEN** creating a change proposal that adds new requirements - **THEN** include only the new requirements under `## ADDED Requirements` - **AND** each requirement SHALL include its complete content - **AND** use the standard structured format for requirements and scenarios #### Scenario: Creating change proposals with modifications - **WHEN** creating a change proposal that modifies existing requirements - **THEN** include the modified requirements under `## MODIFIED Requirements` - **AND** use the same header text as in the current spec (normalized) - **AND** include the complete modified requirement (not a diff) - **AND** optionally annotate what changed with inline comments like `← (was X)` #### Scenario: Creating change proposals with removals - **WHEN** creating a change proposal that removes requirements - **THEN** list them under `## REMOVED Requirements` - **AND** use the normalized header text for identification - **AND** include reason for removal - **AND** document any migration path if applicable The `changes/[name]/specs/` directory SHALL contain: - Delta files showing only what changes - Sections for ADDED, MODIFIED, REMOVED, and RENAMED requirements - Normalized header matching for requirement identification - Complete requirements using the structured format - Clear indication of change type for each requirement #### Scenario: Using standard output symbols - **WHEN** displaying delta operations in CLI output - **THEN** use these standard symbols: - `+` for ADDED (green) - `~` for MODIFIED (yellow) - `-` for REMOVED (red) - `→` for RENAMED (cyan) ### Requirement: Archive Process Enhancement The archive process SHALL programmatically apply delta changes to current specifications using header-based matching. #### Scenario: Archiving changes with deltas - **WHEN** archiving a completed change - **THEN** the archive command SHALL: 1. Parse RENAMED sections first and apply renames 2. Parse REMOVED sections and remove by normalized header match 3. Parse MODIFIED sections and replace by normalized header match (using new names if renamed) 4. Parse ADDED sections and append new requirements - **AND** validate that all MODIFIED/REMOVED headers exist in current spec - **AND** validate that ADDED headers don't already exist - **AND** generate the updated spec in the main specs/ directory #### Scenario: Handling conflicts during archive - **WHEN** delta changes conflict with current spec state - **THEN** the archive command SHALL report specific conflicts - **AND** require manual resolution before proceeding - **AND** provide clear guidance on resolving conflicts ================================================ FILE: openspec/changes/archive/2025-08-19-adopt-delta-based-changes/tasks.md ================================================ # Implementation Tasks ## 1. Update Conventions - [x] 1.1 Update openspec-conventions spec with delta-based approach - [x] 1.2 Add Header-Based Requirement Identification - [x] 1.3 Define ADDED/MODIFIED/REMOVED/RENAMED sections - [x] 1.4 Document standard output symbols (+ ~ - →) - [x] 1.5 Update openspec/README.md with delta-based conventions - [x] 1.6 Update examples to use delta format ## 2. Update Diff Command - [ ] 2.1 Update cli-diff spec with requirement-level comparison - [ ] 2.2 Parse specs into requirement-level structures - [ ] 2.3 Apply deltas to generate future state - [ ] 2.4 Implement side-by-side comparison view (changes only) - [ ] 2.5 Add tests for requirement-level comparison - [ ] 2.6 Add tests for side-by-side view formatting ## 3. Update Archive Command - [x] 3.1 Update cli-archive spec with delta processing behavior - [x] 3.2 Implement requirement-block extractor that preserves exact headers (`### Requirement: [Name]`) and captures full content (including scenarios) - [x] 3.3 Implement normalized header matching (trim-only, case-sensitive) - [x] 3.4 Parse delta sections (ADDED/MODIFIED/REMOVED/RENAMED) - [x] 3.5 New spec creation when target spec does not exist - [x] 3.5.1 Auto-generate minimal skeleton: `# [Spec Name] Specification`, `## Purpose` placeholder, `## Requirements` - [x] 3.5.2 Allow only ADDED operations for non-existent specs; abort if MODIFIED/REMOVED/RENAMED present - [x] 3.6 Apply changes in order: RENAMED → REMOVED → MODIFIED → ADDED - [x] 3.7 Validation and conflict checks - [x] 3.7.1 MODIFIED/REMOVED requirements exist (after applying rename mappings) - [x] 3.7.2 ADDED requirements don't already exist (consider post-rename state) - [x] 3.7.3 RENAMED FROM headers exist; TO headers don't (including collisions with ADDED) - [x] 3.7.4 No duplicate headers within specs after all operations - [x] 3.7.5 Detect cross-section conflicts (e.g., same requirement in MODIFIED and REMOVED) - [x] 3.7.6 When a rename exists, require MODIFIED to reference the NEW header - [x] 3.8 Atomic updates - [x] 3.8.1 Validate all deltas first; stage updates in-memory per spec - [x] 3.8.2 Single write per spec; abort entire archive on any validation failure (no partial writes) - [x] 3.9 Output and error messaging - [x] 3.9.1 Display per-spec operation counts with symbols: `+` added, `~` modified, `-` removed, `→` renamed - [x] 3.9.2 Optionally display an aggregated totals line across all specs - [x] 3.9.3 Standardize error message format: `[spec] [operation] failed for header "### Requirement: X" — reason`; end with `Aborted. No files were changed.` on failure - [x] 3.10 Idempotency behavior (v1): abort on precondition failures (e.g., ADDED already exists); do not implement no-op detection - [x] 3.11 Tests - [x] 3.11.1 Header normalization (trim-only) matching - [x] 3.11.2 Apply in correct order (RENAMED → REMOVED → MODIFIED → ADDED) - [x] 3.11.3 Validation edge cases (missing headers, duplicates, rename collisions, conflicting sections) - [x] 3.11.4 Rename + modify interplay (MODIFIED uses new header) - [x] 3.11.5 New spec creation via skeleton - [x] 3.11.6 Multi-spec mixed operations with independent validation and write ## Notes - Archive command is critical path - must work reliably - All new changes must use delta format - Header normalization: normalize(header) = trim(header) - Diff command shows only changed requirements in side-by-side comparison ================================================ FILE: openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/design.md ================================================ # Design: Verb–Noun CLI Structure Adoption ## Overview We will make verb commands (`list`, `show`, `validate`, `diff`, `archive`) the primary interface and keep noun commands (`spec`, `change`) as deprecated aliases for one release. ## Decisions 1. Keep routing centralized in `src/cli/index.ts`. 2. Add `--specs`/`--changes` to `openspec list`, with `--changes` as default. 3. Show deprecation warnings for `openspec change list` and, more generally, for any `openspec change ...` and `openspec spec ...` subcommands. 4. Do not change `show`/`validate` behavior beyond help text; they already support `--type` for disambiguation. ## Backward Compatibility All noun-based commands continue to work with clear deprecation warnings directing users to verb-first equivalents. ## Out of Scope JSON output parity for `openspec list` across modes and `show --specs/--changes` discovery are follow-ups. ================================================ FILE: openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/proposal.md ================================================ # Change: Adopt Verb–Noun CLI Structure (Deprecate Noun-Based Commands) ## Why Most widely used CLIs (git, docker, kubectl) start with an action (verb) followed by the object (noun). This matches how users think: “do X to Y”. Using verbs as top-level commands improves clarity, discoverability, and extensibility. ## What Changes - Promote top-level verb commands as primary entry points: `list`, `show`, `validate`, `diff`, `archive`. - Deprecate noun-based top-level commands: `openspec spec ...` and `openspec change ...`. - Introduce consistent noun scoping via flags where applicable (e.g., `--changes`, `--specs`) and keep smart defaults. - Clarify disambiguation for `show` and `validate` when names collide. ### Mappings (From → To) - **List** - From: `openspec change list` - To: `openspec list --changes` (default), or `openspec list --specs` - **Show** - From: `openspec spec show ` / `openspec change show ` - To: `openspec show ` with auto-detect, use `--type spec|change` if ambiguous - **Validate** - From: `openspec spec validate ` / `openspec change validate ` - To: `openspec validate --type spec|change`, or bulk: `openspec validate --specs` / `--changes` / `--all` ### Backward Compatibility - Keep `openspec spec` and `openspec change` available with deprecation warnings for one release cycle. - Update help text to point users to the verb–noun alternatives. ## Impact - **Affected specs**: - `cli-list`: Add support for `--specs` and explicit `--changes` (default remains changes) - `openspec-conventions`: Add explicit requirement establishing verb–noun CLI design and deprecation guidance - **Affected code**: - `src/cli/index.ts`: Un-deprecate top-level `list`; mark `change list` as deprecated; ensure help text and warnings align - `src/core/list.ts`: Support listing specs via `--specs` and default to changes; shared output shape - Optional follow-ups: tighten `show`/`validate` help and ambiguity handling ## Explicit Changes **CLI Design** - From: Mixed model with nouns (`spec`, `change`) and some top-level verbs; `openspec list` currently deprecated - To: Verbs as primary: `openspec list|show|validate|diff|archive`; nouns scoped via flags or item ids; noun commands deprecated - Reason: Align with common CLIs; improve UX; simpler mental model - Impact: Non-breaking with deprecation period; users migrate incrementally **Listing Behavior** - From: `openspec change list` (primary), `openspec list` (deprecated) - To: `openspec list` as primary, defaulting to `--changes`; add `--specs` to list specs - Reason: Consistent verb–noun style; better discoverability - Impact: New option; preserves existing behavior via default ## Rollout and Deprecation Policy - Show deprecation warnings on noun-based commands for one release. - Document new usage in `openspec/README.md` and CLI help. - After one release, consider removing noun-based commands, or keep as thin aliases without warnings. ## Open Questions - Should `show` also accept `--changes`/`--specs` for discovery without an id? (Out of scope here; current auto-detect and `--type` remain.) ================================================ FILE: openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/specs/cli-list/spec.md ================================================ # Delta: CLI List Command ## MODIFIED Requirements ### Requirement: Command Execution The command SHALL scan and analyze either active changes or specs based on the selected mode. #### Scenario: Scanning for changes (default) - **WHEN** `openspec list` is executed without flags - **THEN** scan the `openspec/changes/` directory for change directories - **AND** exclude the `archive/` subdirectory from results - **AND** parse each change's `tasks.md` file to count task completion #### Scenario: Scanning for specs - **WHEN** `openspec list --specs` is executed - **THEN** scan the `openspec/specs/` directory for capabilities - **AND** read each capability's `spec.md` - **AND** parse requirements to compute requirement counts ### Requirement: Output Format The command SHALL display items in a clear, readable table format with mode-appropriate progress or counts. #### Scenario: Displaying change list (default) - **WHEN** displaying the list of changes - **THEN** show a table with columns: - Change name (directory name) - Task progress (e.g., "3/5 tasks" or "✓ Complete") #### Scenario: Displaying spec list - **WHEN** displaying the list of specs - **THEN** show a table with columns: - Spec id (directory name) - Requirement count (e.g., "requirements 12") ### Requirement: Empty State The command SHALL provide clear feedback when no items are present for the selected mode. #### Scenario: Handling empty state (changes) - **WHEN** no active changes exist (only archive/ or empty changes/) - **THEN** display: "No active changes found." #### Scenario: Handling empty state (specs) - **WHEN** no specs directory exists or contains no capabilities - **THEN** display: "No specs found." ### Requirement: Flags The command SHALL accept flags to select the noun being listed. #### Scenario: Selecting specs - **WHEN** `--specs` is provided - **THEN** list specs instead of changes #### Scenario: Selecting changes - **WHEN** `--changes` is provided - **THEN** list changes explicitly (same as default behavior) ================================================ FILE: openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/specs/openspec-conventions/spec.md ================================================ # Delta: OpenSpec Conventions — Verb–Noun CLI Design ## ADDED Requirements ### Requirement: Verb–Noun CLI Command Structure OpenSpec CLI design SHALL use verbs as top-level commands with nouns provided as arguments or flags for scoping. #### Scenario: Verb-first command discovery - **WHEN** a user runs a command like `openspec list` - **THEN** the verb communicates the action clearly - **AND** nouns refine scope via flags or arguments (e.g., `--changes`, `--specs`) #### Scenario: Backward compatibility for noun commands - **WHEN** users run noun-prefixed commands such as `openspec spec ...` or `openspec change ...` - **THEN** the CLI SHALL continue to support them for at least one release - **AND** display a deprecation warning that points to verb-first alternatives #### Scenario: Disambiguation guidance - **WHEN** item names are ambiguous between changes and specs - **THEN** `openspec show` and `openspec validate` SHALL accept `--type spec|change` - **AND** the help text SHALL document this clearly ================================================ FILE: openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/tasks.md ================================================ # Implementation Tasks ## 1. CLI Behavior and Help - [x] 1.1 Un-deprecate top-level `openspec list`; mark `change list` as deprecated with warning that points to `openspec list` - [x] 1.2 Add support to list specs via `openspec list --specs` and keep `--changes` as default - [x] 1.3 Update command descriptions and `--help` output to emphasize verb–noun pattern - [x] 1.4 Keep `openspec spec ...` and `openspec change ...` commands working but print deprecation notices ## 2. Core List Logic - [x] 2.1 Extend `src/core/list.ts` to accept a mode: `changes` (default) or `specs` - [x] 2.2 Implement `specs` listing: scan `openspec/specs/*/spec.md`, compute requirement count via parser, format output consistently - [x] 2.3 Share output structure for both modes; preserve current text table; ensure JSON parity in future change ## 3. Specs and Conventions - [x] 3.1 Update `openspec/specs/cli-list/spec.md` to document `--specs` (and default to changes) - [x] 3.2 Update `openspec/specs/openspec-conventions/spec.md` with a requirement for verb–noun CLI design and deprecation guidance ## 4. Tests and Docs - [x] 4.1 Update tests: ensure `openspec list` works for changes and specs; keep `change list` tests but assert warning - [ ] 4.2 Update README and any usage docs to show new primary commands - [ ] 4.3 Add migration notes in repo CHANGELOG or README ## 5. Follow-ups (Optional, not in this change) - [ ] 5.1 Consider `openspec show --specs/--changes` for discovery without ids - [ ] 5.2 Consider JSON output for `openspec list` with `--json` for both modes ================================================ FILE: openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/proposal.md ================================================ ## Why Currently, users must validate changes and specs individually by specifying each ID. This creates friction when: - Teams want to validate all changes/specs before a release - Developers need to ensure consistency across multiple related changes - Users run validation commands without arguments and receive errors instead of helpful guidance - The subcommand structure requires users to know in advance whether they're validating a change or spec ## What Changes - Add new top-level `validate` command with intuitive flags (--all, --changes, --specs) - Enhance existing `change validate` and `spec validate` to support interactive selection (backwards compatibility) - Interactive selection by default when no arguments provided - Support direct item validation: `openspec validate ` with automatic type detection ## Impact - New specs to create: cli-validate - Specs to enhance: cli-change, cli-spec (for backwards compatibility) - Affected code: src/cli/index.ts, src/commands/validate.ts (new), src/commands/spec.ts, src/commands/change.ts ================================================ FILE: openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/specs/cli-change/spec.md ================================================ # CLI Change Command Spec ## ADDED Requirements ### Requirement: Interactive validation selection The change validate command SHALL support interactive selection when no change name is provided. #### Scenario: Interactive change selection for validation - **WHEN** executing `openspec change validate` without arguments - **THEN** display an interactive list of available changes - **AND** allow the user to select a change to validate - **AND** validate the selected change #### Scenario: Non-interactive fallback keeps current behavior - **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0` - **WHEN** executing `openspec change validate` without a change name - **THEN** do not prompt interactively - **AND** print the existing hint including available change IDs - **AND** set `process.exitCode = 1` ================================================ FILE: openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/specs/cli-spec/spec.md ================================================ # CLI Spec Command Spec ## ADDED Requirements ### Requirement: Interactive spec validation The spec validate command SHALL support interactive selection when no spec-id is provided. #### Scenario: Interactive spec selection for validation - **WHEN** executing `openspec spec validate` without arguments - **THEN** display an interactive list of available specs - **AND** allow the user to select a spec to validate - **AND** validate the selected spec - **AND** maintain all existing validation options (--strict, --json) #### Scenario: Non-interactive fallback keeps current behavior - **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0` - **WHEN** executing `openspec spec validate` without a spec-id - **THEN** do not prompt interactively - **AND** print the existing error message for missing spec-id - **AND** set non-zero exit code ================================================ FILE: openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/specs/cli-validate/spec.md ================================================ # CLI Validate Command Spec ## ADDED Requirements ### Requirement: Top-level validate command The CLI SHALL provide a top-level `validate` command for validating changes and specs with flexible selection options. #### Scenario: Interactive validation selection - **WHEN** executing `openspec validate` without arguments - **THEN** prompt user to select what to validate (all, changes, specs, or specific item) - **AND** perform validation based on selection - **AND** display results with appropriate formatting #### Scenario: Non-interactive environments do not prompt - **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0` - **WHEN** executing `openspec validate` without arguments - **THEN** do not prompt interactively - **AND** print a helpful hint listing available commands/flags and exit with code 1 #### Scenario: Direct item validation - **WHEN** executing `openspec validate ` - **THEN** automatically detect if item is a change or spec - **AND** validate the specified item - **AND** display validation results ### Requirement: Bulk and filtered validation The validate command SHALL support flags for bulk validation (--all) and filtered validation by type (--changes, --specs). #### Scenario: Validate everything - **WHEN** executing `openspec validate --all` - **THEN** validate all changes in openspec/changes/ (excluding archive) - **AND** validate all specs in openspec/specs/ - **AND** display a summary showing passed/failed items - **AND** exit with code 1 if any validation fails #### Scenario: Scope of bulk validation - **WHEN** validating with `--all` or `--changes` - **THEN** include all change proposals under `openspec/changes/` - **AND** exclude the `openspec/changes/archive/` directory - **WHEN** validating with `--specs` - **THEN** include all specs that have a `spec.md` under `openspec/specs//spec.md` #### Scenario: Validate all changes - **WHEN** executing `openspec validate --changes` - **THEN** validate all changes in openspec/changes/ (excluding archive) - **AND** display results for each change - **AND** show summary statistics #### Scenario: Validate all specs - **WHEN** executing `openspec validate --specs` - **THEN** validate all specs in openspec/specs/ - **AND** display results for each spec - **AND** show summary statistics ### Requirement: Validation options and progress indication The validate command SHALL support standard validation options (--strict, --json) and display progress during bulk operations. #### Scenario: Strict validation - **WHEN** executing `openspec validate --all --strict` - **THEN** apply strict validation to all items - **AND** treat warnings as errors - **AND** fail if any item has warnings or errors #### Scenario: JSON output - **WHEN** executing `openspec validate --all --json` - **THEN** output validation results as JSON - **AND** include detailed issues for each item - **AND** include summary statistics #### Scenario: JSON output schema for bulk validation - **WHEN** executing `openspec validate --all --json` (or `--changes` / `--specs`) - **THEN** output a JSON object with the following shape: - `items`: Array of objects with fields `{ id: string, type: "change"|"spec", valid: boolean, issues: Issue[], durationMs: number }` - `summary`: Object `{ totals: { items: number, passed: number, failed: number }, byType: { change?: { items: number, passed: number, failed: number }, spec?: { items: number, passed: number, failed: number } } }` - `version`: String identifier for the schema (e.g., `"1.0"`) - **AND** exit with code 1 if any `items[].valid === false` Where `Issue` follows the existing per-item validation report shape `{ level: "ERROR"|"WARNING"|"INFO", path: string, message: string }`. #### Scenario: Show validation progress - **WHEN** validating multiple items (--all, --changes, or --specs) - **THEN** show progress indicator or status updates - **AND** indicate which item is currently being validated - **AND** display running count of passed/failed items #### Scenario: Concurrency limits for performance - **WHEN** validating multiple items - **THEN** run validations with a bounded concurrency (e.g., 4–8 in parallel) - **AND** ensure progress indicators remain responsive ### Requirement: Item type detection and ambiguity handling The validate command SHALL handle ambiguous names and explicit type overrides to ensure clear, deterministic behavior. #### Scenario: Direct item validation with automatic type detection - **WHEN** executing `openspec validate ` - **THEN** if `` uniquely matches a change or a spec, validate that item #### Scenario: Ambiguity between change and spec names - **GIVEN** `` exists both as a change and as a spec - **WHEN** executing `openspec validate ` - **THEN** print an ambiguity error explaining both matches - **AND** suggest passing `--type change` or `--type spec`, or using `openspec change validate` / `openspec spec validate` - **AND** exit with code 1 without performing validation #### Scenario: Unknown item name - **WHEN** the `` matches neither a change nor a spec - **THEN** print a not-found error - **AND** show nearest-match suggestions when available - **AND** exit with code 1 #### Scenario: Explicit type override - **WHEN** executing `openspec validate --type change ` - **THEN** treat `` as a change ID and validate it (skipping auto-detection) - **WHEN** executing `openspec validate --type spec ` - **THEN** treat `` as a spec ID and validate it (skipping auto-detection) ### Requirement: Interactivity controls - The CLI SHALL respect `--no-interactive` to disable prompts. - The CLI SHALL respect `OPEN_SPEC_INTERACTIVE=0` to disable prompts globally. - Interactive prompts SHALL only be shown when stdin is a TTY and interactivity is not disabled. #### Scenario: Disabling prompts via flags or environment - **WHEN** `openspec validate` is executed with `--no-interactive` or with environment `OPEN_SPEC_INTERACTIVE=0` - **THEN** the CLI SHALL not display interactive prompts - **AND** SHALL print non-interactive hints or chosen outputs as appropriate ================================================ FILE: openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/tasks.md ================================================ # Implementation Tasks ## 1. Change Command: Interactive Validation Selection - [x] 1.1 Add `--no-interactive` flag to `change validate` in `src/cli/index.ts` - [x] 1.2 Implement interactivity gate respecting TTY and `OPEN_SPEC_INTERACTIVE=0` in `src/commands/change.ts` - [x] 1.3 When no `[change-name]` is provided and interactivity is allowed, prompt with a list of active changes (exclude `archive/`) and validate the selected one - [x] 1.4 Preserve current non-interactive fallback: print available change IDs and hint, set `process.exitCode = 1` - [x] 1.5 Tests: add coverage for interactive and non-interactive flows - Added `test/commands/change.interactive-validate.test.ts` ## 2. Spec Command: Interactive Validation Selection - [x] 2.1 Make `spec validate` accept optional `[spec-id]` in `src/commands/spec.ts` registration - [x] 2.2 Add `--no-interactive` flag to `spec validate` - [x] 2.3 Implement interactivity gate respecting TTY and `OPEN_SPEC_INTERACTIVE=0` - [x] 2.4 When no `[spec-id]` provided and interactivity allowed, prompt to select from `openspec/specs/*/spec.md` and validate the selected spec - [x] 2.5 Preserve current non-interactive fallback when no spec-id and no interactivity: print existing error and exit code non-zero - [x] 2.6 Tests: add coverage for interactive and non-interactive flows - Added `test/commands/spec.interactive-validate.test.ts` ## 3. New Top-level `validate` Command - [x] 3.1 Add `validate` command in `src/cli/index.ts` - Options: `--all`, `--changes`, `--specs`, `--type `, `--strict`, `--json`, `--no-interactive` - Usage: `openspec validate [item-name]` - [x] 3.2 Create `src/commands/validate.ts` implementing: - [x] 3.2.1 Interactive selector when no args (choices: All, Changes, Specs, Specific item) - [x] 3.2.2 Non-interactive fallback with helpful hint and exit code 1 - [x] 3.2.3 Direct item validation with automatic type detection - [x] 3.2.4 Ambiguity error when name exists as both change and spec; suggest `--type` or subcommands - [x] 3.2.5 Unknown item handling with nearest-match suggestions - [x] 3.2.6 Bulk validation for `--all`, `--changes`, `--specs` (exclude `openspec/changes/archive/`) - [x] 3.2.7 Respect `--strict` and `--json` options; JSON shape per spec - [x] 3.2.8 Exit with code 1 if any validation fails - [x] 3.2.9 Bounded concurrency (default 4–8) for bulk validation - [x] 3.2.10 Progress indication during bulk runs (current item, running counts) ## 4. Utilities and Shared Helpers - [x] 4.1 Add `src/utils/interactive.ts` with `isInteractive(stdin: NodeJS.ReadStream, noInteractiveFlag?: boolean): boolean` - Considers: `process.stdin.isTTY`, `--no-interactive`, `OPEN_SPEC_INTERACTIVE=0` - [x] 4.2 Add `src/utils/item-discovery.ts` with: - `getActiveChangeIds(root = process.cwd()): Promise` (exclude `archive/`) - `getSpecIds(root = process.cwd()): Promise` (folders with `spec.md`) - [ ] 4.3 Optional: `src/utils/concurrency.ts` helper for bounded parallelism - [x] 4.4 Reuse `src/core/validation/validator.ts` for item validation ## 5. JSON Output (Bulk Validation) - [x] 5.1 Implement JSON schema: - `items: Array<{ id: string, type: "change"|"spec", valid: boolean, issues: Issue[], durationMs: number }>` - `summary: { totals: { items: number, passed: number, failed: number }, byType: { change?: { items: number, passed: number, failed: number }, spec?: { items: number, passed: number, failed: number } } }` - `version: "1.0"` - [x] 5.2 Ensure process exit code is 1 if any `items[].valid === false` - [x] 5.3 Tests for JSON shape (keys, types, counts) and exit code behavior - Added `test/commands/validate.test.ts` ## 6. Progress and UX - [x] 6.1 Use `ora` or minimal console progress to show current item and running counts - [x] 6.2 Keep output stable in `--json` mode (no extra logs to stdout; use stderr for progress if needed) - [x] 6.3 Ensure responsiveness with concurrency limits ## 7. Tests - [x] 7.1 Add top-level validate tests: `test/commands/validate.test.ts` - Includes non-interactive hint, --all JSON, --specs with concurrency, ambiguity error - [ ] 7.2 Add unit tests for `isInteractive` and item discovery helpers - [x] 7.3 Extend existing change/spec command tests to cover interactive `validate` - Added `test/commands/change.interactive-validate.test.ts`, `test/commands/spec.interactive-validate.test.ts` ## 8. CLI Help and Docs - [x] 8.1 Update command descriptions/options in `src/cli/index.ts` - [x] 8.2 Verify help output includes `validate` command and flags - [x] 8.3 Ensure existing specs under `openspec/changes/bulk-validation-interactive-selection/specs/*` remain satisfied ## 9. Non-functional - [x] 9.1 Code style and types: explicit types for exported APIs; avoid `any` - [x] 9.2 No linter errors; stable formatting; avoid unrelated refactors - [x] 9.3 Maintain existing behavior for unaffected commands ## 10. Acceptance Criteria Mapping - [x] AC-1: `openspec change validate` interactive selection when no arg (TTY only; respects `--no-interactive`/env) — matches cli-change spec - [x] AC-2: `openspec spec validate` interactive selection when no arg (TTY only; respects `--no-interactive`/env) — matches cli-spec spec - [x] AC-3: New `openspec validate` supports interactive selection, bulk/filtered validation, JSON schema, progress, concurrency, exit codes — matches cli-validate spec ================================================ FILE: openspec/changes/archive/2025-08-19-fix-update-tool-selection/proposal.md ================================================ # Fix Update Command Tool Selection ## Problem The `openspec update` command currently forces the creation/update of CLAUDE.md regardless of which AI tool was selected during initialization. This violates the tool-agnostic design principle and creates confusion for users who selected different AI assistants. Additionally, different team members may use different AI tools, so we cannot rely on a shared configuration file. ## Solution Modify the update command to: 1. Only update AI tool configuration files that already exist 2. Never create new AI tool configuration files 3. Always update the core OpenSpec files (README.md, etc.) ## Implementation - Remove hardcoded CLAUDE.md update from update command - Implement file existence check before updating any AI tool config - Update each existing AI tool config file with its appropriate markers - No configuration file needed (avoids team conflicts) ## Success Criteria - Update command only modifies existing AI tool configuration files - No new AI tool files created during update - Team members can use different AI tools without conflicts - Existing projects continue to work (backward compatibility) ## Why Users need predictable, tool-agnostic behavior from `openspec update`. Creating or forcing updates for AI tool files that a project does not use causes confusion and merge conflicts. Restricting updates to existing files and always updating core OpenSpec files keeps the workflow consistent for mixed-tool teams. ## What Changes - **cli-update:** Modify update behavior to update only existing AI tool configuration files and never create new ones; always update core OpenSpec files and display an ASCII-safe success message. ## ADDED Requirements Removed from proposal to follow conventions. See `specs/cli-update/spec.md` for the delta requirements content. ================================================ FILE: openspec/changes/archive/2025-08-19-fix-update-tool-selection/specs/cli-update/spec.md ================================================ ## ADDED Requirements ### Requirement: Tool-Agnostic Updates The update command SHALL update only existing AI tool configuration files and SHALL NOT create new ones. #### Scenario: Updating existing tool files - **WHEN** a user runs `openspec update` - **THEN** update each AI tool configuration file that exists (e.g., CLAUDE.md, COPILOT.md) - **AND** do not create missing tool configuration files - **AND** preserve user content outside OpenSpec markers ### Requirement: Core Files Always Updated The update command SHALL always update the core OpenSpec files and display an ASCII-safe success message. #### Scenario: Successful update - **WHEN** the update completes successfully - **THEN** replace `openspec/README.md` with the latest template - **AND** update existing AI tool configuration files within markers - **AND** display the message: "Updated OpenSpec instructions" ================================================ FILE: openspec/changes/archive/2025-08-19-fix-update-tool-selection/tasks.md ================================================ # Implementation Tasks ## 1. Update Update Command - [x] Remove hardcoded CLAUDE.md update from `src/core/update.ts` - [x] Add logic to check for existing AI tool configuration files - [x] Update only existing files using their appropriate configurators - [x] Iterate through all registered configurators to check for existing files ## 2. Update Configurator Registry - [x] Add method to get all configurators for update command - [x] Ensure each configurator can check if its file exists ## 3. Add Tests - [x] Test update command with only CLAUDE.md present - [x] Test update command with no AI tool files present - [x] Test update command with multiple AI tool files present - [x] Test that update never creates new AI tool files ## 4. Update Documentation - [x] Update README to clarify team-friendly behavior - [x] Document that update only modifies existing files ================================================ FILE: openspec/changes/archive/2025-08-19-improve-validate-error-messages/proposal.md ================================================ # improve-validate-error-messages ## Why Developers struggle to resolve validation failures because current errors lack actionable guidance. Common issues include: missing deltas, missing required sections, and misformatted scenarios that are silently ignored. Without clear remediation steps, users cannot quickly correct structure or formatting, leading to frustration and rework. Improving error messages with concrete fixes, file/section hints, and suggested commands will significantly reduce time-to-green and make OpenSpec more approachable. ## What Changes - Validation errors SHALL include specific remediation steps (what to change and where). - "No deltas found" error SHALL guide users to create `specs/` with proper delta headers and suggest debug commands. - Missing required sections (Spec: Purpose/Requirements; Change: Why/What Changes) SHALL include expected header names and a minimal skeleton example. - Likely misformatted scenarios (bulleted WHEN/THEN/AND) SHALL emit a targeted warning explaining the `#### Scenario:` format and show a conversion template. - All reported issues SHALL include the source file path and structured location (e.g., `deltas[0].requirements[0]`). - Non-JSON output SHOULD end with a short "Next steps" footer when invalid. ## Impact - Affected CLI: validate - Affected code: - `src/commands/validate.ts` - `src/core/validation/validator.ts` - `src/core/validation/constants.ts` - `src/core/parsers/*` (wrapping thrown errors with richer context) ================================================ FILE: openspec/changes/archive/2025-08-19-improve-validate-error-messages/specs/cli-validate/spec.md ================================================ # Validate Command ## ADDED Requirements ### Requirement: Validation SHALL provide actionable remediation steps Validation output SHALL include specific guidance to fix each error, including expected structure, example headers, and suggested commands to verify fixes. #### Scenario: No deltas found in change - **WHEN** validating a change with zero parsed deltas - **THEN** show error "No deltas found" with guidance: - Ensure `openspec/changes/{id}/specs/` exists with `.md` files - Use delta headers: `## ADDED Requirements`, `## MODIFIED Requirements`, `## REMOVED Requirements`, `## RENAMED Requirements` - Each requirement must include at least one `#### Scenario:` block - Try: `openspec change show {id} --json --deltas-only` to inspect what was parsed #### Scenario: Missing required sections - **WHEN** a required section is missing - **THEN** the validator SHALL include expected header names and a minimal skeleton: - For Spec: `## Purpose`, `## Requirements` - For Change: `## Why`, `## What Changes` - Show an example snippet of the missing section ### Requirement: Validator SHALL detect likely misformatted scenarios and warn with a fix The validator SHALL recognize bulleted lines that look like scenarios (e.g., lines beginning with WHEN/THEN/AND) and emit a targeted warning with a conversion example to `#### Scenario:`. #### Scenario: Bulleted WHEN/THEN under a Requirement - **WHEN** bullets that start with WHEN/THEN/AND are found under a requirement without any `#### Scenario:` headers - **THEN** emit warning: "Scenarios must use '#### Scenario:' headers", and show a conversion template: ``` #### Scenario: Short name - **WHEN** ... - **THEN** ... - **AND** ... ``` ### Requirement: All issues SHALL include file paths and structured locations Error, warning, and info messages SHALL include: - Source file path (`openspec/changes/{id}/proposal.md`, `.../specs/{cap}/spec.md`) - Structured path (e.g., `deltas[0].requirements[0].scenarios`) #### Scenario: Zod validation error - **WHEN** a schema validation fails - **THEN** the message SHALL include `file`, `path`, and a remediation hint if applicable ### Requirement: Invalid results SHALL include a Next steps footer in human-readable output The CLI SHALL append a Next steps footer when the item is invalid and not using `--json`, including: - Summary line with counts - Top-3 guidance bullets (contextual to the most frequent or blocking errors) - A suggestion to re-run with `--json` and/or the debug command #### Scenario: Change invalid summary - **WHEN** a change validation fails - **THEN** print "Next steps" with 2-3 targeted bullets and suggest `openspec change show --json --deltas-only` ================================================ FILE: openspec/changes/archive/2025-08-19-improve-validate-error-messages/tasks.md ================================================ ## 1. Enhance validation messages - [x] 1.1 Add remediation guidance for "No deltas found" - [x] 1.2 Include file path and structured path in all issues - [x] 1.3 Improve messages for missing required sections (Spec, Change) - [x] 1.4 Detect likely misformatted scenarios and warn with conversion example - [x] 1.5 Add "Next steps" footer for non-JSON invalid output ## 2. Update constants and helpers - [x] 2.1 Centralize guidance snippets in `VALIDATION_MESSAGES` - [x] 2.2 Provide minimal skeleton examples for missing sections ## 3. Parser integration - [x] 3.1 Capture parser-thrown errors and wrap with richer context - [x] 3.2 Add file/section references to surfaced parser errors ## 4. Tests - [x] 4.1 Unit tests for validator message composition - [x] 4.2 CLI integration tests for human-readable output (with footer) - [x] 4.3 JSON mode tests (structure unchanged, content enriched) ================================================ FILE: openspec/changes/archive/2025-08-19-structured-spec-format/proposal.md ================================================ ## Why OpenSpec specifications lack a consistent structure that makes sections visually identifiable and programmatically parseable across different specs. This makes it harder to maintain consistency and build tooling. ## What Changes **Specification Format Section** - From: No formal structure requirements for specifications - To: Structured format with `### Requirement:` and `#### Scenario:` headers - Reason: Visual consistency and parseability across all specs - Impact: Non-breaking - existing specs can migrate gradually **Keyword Formatting** - From: Inconsistent use of WHEN/THEN/AND keywords - To: Bold keywords (**WHEN**, **THEN**, **AND**) in scenario bullets - Reason: Improved readability and consistent visual hierarchy - Impact: Non-breaking - formatting enhancement only **Format Flexibility** - From: Implicit understanding that different content needs different formats - To: Explicit allowance for alternative formats (OpenAPI, JSON Schema, etc.) - Reason: Address concern that not all specs fit requirement/scenario pattern - Impact: Non-breaking - clarifies existing practice **Migration Guidelines** - From: No migration guidance - To: Documented gradual migration approach - Reason: Allows incremental adoption without disrupting existing specs - Impact: Non-breaking - opt-in migration as specs are modified ## Impact - Affected specs: openspec-conventions (enhancement to existing capability) - Affected code: None initially - this is a documentation standard enhancement - Migration: Gradual - existing specs migrate as they're modified - Tooling: Enables future parsing tools but doesn't require them ================================================ FILE: openspec/changes/archive/2025-08-19-structured-spec-format/specs/openspec-conventions/spec.md ================================================ # OpenSpec Conventions Specification ## ADDED Requirements ### Requirement: Structured Format Adoption Behavioral specifications SHALL adopt the structured format with `### Requirement:` and `#### Scenario:` headers as the default. #### Scenario: Use structured headings for behavior - **WHEN** documenting behavioral requirements - **THEN** use `### Requirement:` for requirements - **AND** use `#### Scenario:` for scenarios with bold WHEN/THEN/AND keywords ## Purpose OpenSpec conventions SHALL define how system capabilities are documented, how changes are proposed and tracked, and how specifications evolve over time. This meta-specification serves as the source of truth for OpenSpec's own conventions. ## Core Principles The system SHALL follow these principles: - Specs reflect what IS currently built and deployed - Changes contain proposals for what SHOULD be changed - AI drives the documentation process - Specs are living documentation kept in sync with deployed code ## Directory Structure WHEN an OpenSpec project is initialized THEN it SHALL have this structure: ``` openspec/ ├── project.md # Project-specific context ├── README.md # AI assistant instructions ├── specs/ # Current deployed capabilities │ └── [capability]/ # Single, focused capability │ ├── spec.md # WHAT and WHY │ └── design.md # HOW (optional, for established patterns) └── changes/ # Proposed changes ├── [change-name]/ # Descriptive change identifier │ ├── proposal.md # Why, what, and impact │ ├── tasks.md # Implementation checklist │ ├── design.md # Technical decisions (optional) │ └── specs/ # Complete future state │ └── [capability]/ │ └── spec.md # Clean markdown (no diff syntax) └── archive/ # Completed changes └── YYYY-MM-DD-[name]/ ``` ## Specification Format ### Requirement: Structured Format for Behavioral Specs Behavioral specifications SHALL use a structured format with consistent section headers and keywords to ensure visual consistency and parseability. #### Scenario: Writing requirement sections - **WHEN** documenting a requirement in a behavioral specification - **THEN** use a level-3 heading with format `### Requirement: [Name]` - **AND** immediately follow with a SHALL statement describing core behavior - **AND** keep requirement names descriptive and under 50 characters #### Scenario: Documenting scenarios - **WHEN** documenting specific behaviors or use cases - **THEN** use level-4 headings with format `#### Scenario: [Description]` - **AND** use bullet points with bold keywords for steps: - **GIVEN** for initial state (optional) - **WHEN** for conditions or triggers - **THEN** for expected outcomes - **AND** for additional outcomes or conditions #### Scenario: Adding implementation details - **WHEN** a step requires additional detail - **THEN** use sub-bullets under the main step - **AND** maintain consistent indentation - Sub-bullets provide examples or specifics - Keep sub-bullets concise ### Requirement: Format Flexibility The structured format SHALL be the default for behavioral specifications, but alternative formats MAY be used when more appropriate for the content type. #### Scenario: Documenting API specifications - **WHEN** documenting REST API endpoints or GraphQL schemas - **THEN** OpenAPI, GraphQL SDL, or similar formats MAY be used - **AND** the spec SHALL clearly indicate the format being used - **AND** behavioral aspects SHALL still follow the structured format #### Scenario: Documenting data schemas - **WHEN** documenting data structures, database schemas, or configurations - **THEN** JSON Schema, SQL DDL, or similar formats MAY be used - **AND** include the structured format for behavioral rules and constraints #### Scenario: Using simplified format - **WHEN** documenting simple capabilities without complex scenarios - **THEN** a simplified WHEN/THEN format without full structure MAY be used - **AND** this should be consistent within the capability ## Change Storage Convention ### Future State Storage WHEN creating a change proposal THEN store the complete future state of affected specs AND use clean markdown without diff syntax The `changes/[name]/specs/` directory SHALL contain: - Complete spec files as they will exist after the change - Clean markdown without `+` or `-` prefixes - All formatting and structure of the final intended state ### Proposal Format WHEN documenting what changes THEN the proposal SHALL explicitly describe each change: ```markdown **[Section or Behavior Name]** - From: [current state/requirement] - To: [future state/requirement] - Reason: [why this change is needed] - Impact: [breaking/non-breaking, who's affected] ``` This explicit format compensates for not having inline diffs and ensures reviewers understand exactly what will change. ## Change Lifecycle The change process SHALL follow these states: 1. **Propose**: AI creates change with future state specs and explicit proposal 2. **Review**: Humans review proposal and future state 3. **Approve**: Change is approved for implementation 4. **Implement**: Follow tasks.md checklist (can span multiple PRs) 5. **Deploy**: Changes are deployed to production 6. **Update**: Specs in `specs/` are updated to match deployed reality 7. **Archive**: Change is moved to `archive/YYYY-MM-DD-[name]/` ## Viewing Changes WHEN reviewing proposed changes THEN reviewers can compare using: - GitHub PR diff view when changes are committed - Command line: `diff -u specs/[capability]/spec.md changes/[name]/specs/[capability]/spec.md` - Any visual diff tool comparing current vs future state The system relies on tools to generate diffs rather than storing them. ## Capability Naming Capabilities SHALL use: - Verb-noun patterns (e.g., `user-auth`, `payment-capture`) - Hyphenated lowercase names - Singular focus (one responsibility per capability) - No nesting (flat structure under `specs/`) ## When Changes Require Proposals A proposal SHALL be created for: - New features or capabilities - Breaking changes to existing behavior - Architecture or pattern changes - Performance optimizations that change behavior - Security updates affecting access patterns A proposal is NOT required for: - Bug fixes restoring intended behavior - Typos or formatting fixes - Non-breaking dependency updates - Adding tests for existing behavior - Documentation clarifications ## Why This Approach Clean future state storage provides: - **Readability**: No diff syntax pollution - **AI-compatibility**: Standard markdown that AI tools understand - **Simplicity**: No special parsing or processing needed - **Tool-agnostic**: Any diff tool can show changes - **Clear intent**: Explicit proposals document reasoning The structured format adds: - **Visual Consistency**: Requirement and Scenario prefixes make sections instantly recognizable - **Parseability**: Consistent structure enables tooling and automation - **Flexibility**: Alternative formats supported where appropriate - **Gradual Adoption**: Existing specs can migrate incrementally ================================================ FILE: openspec/changes/archive/2025-08-19-structured-spec-format/tasks.md ================================================ ## 1. Update OpenSpec Conventions Spec - [x] 1.1 Add "Specification Format" section to openspec-conventions - [x] 1.2 Document structured format with Requirement/Scenario headers - [x] 1.3 Define bold keyword usage (WHEN/THEN/AND) for scenarios - [x] 1.4 Include examples demonstrating the format within the spec itself ## 2. Update Documentation - [x] 2.1 Update the "Why This Approach" section with structured format benefits - [x] 2.2 Ensure spec follows its own format as a demonstration ## 3. Update Existing Specs - [x] 3.1 Update cli-init spec to use structured format in Behavior section - [x] 3.2 Update cli-list spec to use structured format in Behavior section - [x] 3.3 Update cli-update spec to use structured format in Behavior section - [x] 3.4 Update cli-diff spec to use structured format in Behavior section - [x] 3.5 Update cli-archive spec to use structured format in Behavior section ================================================ FILE: openspec/changes/archive/2025-09-12-add-view-dashboard-command/proposal.md ================================================ # Change: Add View Dashboard Command ## Why Users need a quick, at-a-glance overview of their OpenSpec project status without running multiple commands. Currently, users must run `openspec list --changes` and `openspec list --specs` separately to understand the project state. A unified dashboard view would improve developer experience and provide immediate insight into project progress. ## What Changes ### Added `openspec view` Command The new command provides an interactive dashboard displaying: - Summary metrics (total specs, requirements, changes, task progress) - Active changes with visual progress bars - Completed changes - Specifications with requirement counts ### Specifications Affected - **cli-view** (NEW): Complete specification for the view dashboard command ## Implementation Details ### File Structure - Created `/src/core/view.ts` implementing the `ViewCommand` class - Registered command in `/src/cli/index.ts` - Reuses existing utilities from `task-progress.ts` and `MarkdownParser` ### Visual Design - Uses Unicode box drawing characters for borders - Color coding: cyan for specs, yellow for active, green for completed - Progress bars using filled (█) and empty (░) blocks - Clean alignment with proper padding ### Technical Approach - Async data fetching from changes and specs directories - Parallel processing of specs and changes - Error handling for missing or invalid data - Maintains consistency with existing list command output ================================================ FILE: openspec/changes/archive/2025-09-12-add-view-dashboard-command/specs/cli-view/spec.md ================================================ # CLI View Command - Changes ## ADDED Requirements ### Requirement: Dashboard Display The system SHALL provide a `view` command that displays a dashboard overview of specs and changes. #### Scenario: Basic dashboard display - **WHEN** user runs `openspec view` - **THEN** system displays a formatted dashboard with sections for summary, active changes, completed changes, and specifications #### Scenario: No OpenSpec directory - **WHEN** user runs `openspec view` in a directory without OpenSpec - **THEN** system displays error message "✗ No openspec directory found" ### Requirement: Summary Section The dashboard SHALL display a summary section with key project metrics. #### Scenario: Complete summary display - **WHEN** dashboard is rendered with specs and changes - **THEN** system shows total number of specifications and requirements - **AND** shows number of active changes in progress - **AND** shows number of completed changes - **AND** shows overall task progress percentage #### Scenario: Empty project summary - **WHEN** no specs or changes exist - **THEN** summary shows zero counts for all metrics ### Requirement: Active Changes Display The dashboard SHALL show active changes with visual progress indicators. #### Scenario: Active changes with progress bars - **WHEN** there are in-progress changes with tasks - **THEN** system displays each change with change name left-aligned - **AND** visual progress bar using Unicode characters - **AND** percentage completion on the right #### Scenario: No active changes - **WHEN** all changes are completed or no changes exist - **THEN** active changes section is omitted from display ### Requirement: Completed Changes Display The dashboard SHALL list completed changes in a separate section. #### Scenario: Completed changes listing - **WHEN** there are completed changes (all tasks done) - **THEN** system shows them with checkmark indicators in a dedicated section #### Scenario: Mixed completion states - **WHEN** some changes are complete and others active - **THEN** system separates them into appropriate sections ### Requirement: Specifications Display The dashboard SHALL display specifications sorted by requirement count. #### Scenario: Specs listing with counts - **WHEN** specifications exist in the project - **THEN** system shows specs sorted by requirement count (descending) with count labels #### Scenario: Specs with parsing errors - **WHEN** a spec file cannot be parsed - **THEN** system includes it with 0 requirement count ### Requirement: Visual Formatting The dashboard SHALL use consistent visual formatting with colors and symbols. #### Scenario: Color coding - **WHEN** dashboard elements are displayed - **THEN** system uses cyan for specification items - **AND** yellow for active changes - **AND** green for completed items - **AND** dim gray for supplementary text #### Scenario: Progress bar rendering - **WHEN** displaying progress bars - **THEN** system uses filled blocks (█) for completed portions and light blocks (░) for remaining ### Requirement: Error Handling The view command SHALL handle errors gracefully. #### Scenario: File system errors - **WHEN** file system operations fail - **THEN** system continues with available data and omits inaccessible items #### Scenario: Invalid data structures - **WHEN** specs or changes have invalid format - **THEN** system skips invalid items and continues rendering ================================================ FILE: openspec/changes/archive/2025-09-12-add-view-dashboard-command/tasks.md ================================================ # Implementation Tasks ## Design Phase - [x] Research existing list command implementation - [x] Design dashboard layout and information architecture - [x] Choose appropriate command verb (`view`) - [x] Define visual elements (progress bars, colors, layout) ## Core Implementation - [x] Create ViewCommand class in `/src/core/view.ts` - [x] Implement getChangesData method for fetching change information - [x] Implement getSpecsData method for fetching spec information - [x] Implement displaySummary method for summary metrics - [x] Add progress bar visualization with Unicode characters - [x] Implement color coding using chalk ## Integration - [x] Import ViewCommand in CLI index - [x] Register `openspec view` command with commander - [x] Add proper error handling and ora spinner integration - [x] Ensure command appears in help documentation ## Data Processing - [x] Reuse TaskProgress utilities for change progress - [x] Integrate MarkdownParser for spec requirement counting - [x] Handle async operations for file system access - [x] Sort specifications by requirement count ## Testing and Validation - [x] Build project successfully with new command - [x] Test command with sample data - [x] Verify correct requirement counts match list --specs - [x] Test progress bar display for various completion states - [x] Run existing test suite to ensure no regressions - [x] Verify TypeScript compilation with no errors ## Documentation - [x] Add command description in CLI help - [x] Create change proposal documentation - [x] Update README with view command example (if needed) - [x] Add view command to user documentation (if exists) ## Polish - [x] Ensure consistent formatting and alignment - [x] Add helpful footer text referencing list commands - [x] Optimize for terminal width considerations - [x] Review and refine color choices for accessibility ================================================ FILE: openspec/changes/archive/2025-09-29-add-agents-md-config/proposal.md ================================================ # Add AGENTS.md Standard Support To Init/Update ## Summary - Teach `openspec init` to manage a root-level `AGENTS.md` file using the same marker system as `CLAUDE.md`. - Allow `openspec update` to refresh or scaffold that root `AGENTS.md` so AGENTS-compatible tools always receive current instructions. - Keep the existing `openspec/AGENTS.md` template as the canonical source while ensuring assistants that read `AGENTS.md` opt-in instructions get the latest guidance automatically. ## Motivation The README now points teams to AGENTS.md-compatible assistants, but the CLI only manages `CLAUDE.md`. Projects must hand-roll a root `AGENTS.md` file to benefit from the standard, and updates will drift unless maintainers remember to copy content manually. Extending `init` and `update` closes that gap so OpenSpec actually delivers on the promise of first-class AGENTS support. ## Proposal 1. Extend the `openspec init` selection flow with an "AGENTS.md standard" option that creates or refreshes a root `AGENTS.md` file wrapped in OpenSpec markers, mirroring the existing CLAUDE integration. 2. When generating the file, pull the managed content from the same template used in `openspec/AGENTS.md`, ensuring both locations stay in sync. 3. Update `openspec update` so it always refreshes the root `AGENTS.md` (creating it if missing) alongside `openspec/AGENTS.md` and any other configured assistants. 4. Document the new behavior in CLI specs and verify marker handling (no duplicates, preserve user content outside the block) with tests for both commands. ## Out of Scope - Adding additional AGENTS-specific prompts or workflows beyond the shared instructions block. - Non-interactive flags or bulk configuration for multiple standards in one run. - Broader restructuring of how templates are stored or loaded. ## Risks & Mitigations - **Risk:** Accidentally overwriting user-edited content surrounding the managed block. - **Mitigation:** Reuse the existing marker-update helper shared with `CLAUDE.md`, and add tests that cover files containing custom text before and after the block. - **Risk:** Divergence between `openspec/AGENTS.md` and the root file. - **Mitigation:** Source the root file content from the canonical template rather than duplicating strings inline. - **Risk:** Confusion about when the file is created. - **Mitigation:** Log creation vs update, and ensure help text references the AGENTS option during `init`. ================================================ FILE: openspec/changes/archive/2025-09-29-add-agents-md-config/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: AI Tool Configuration The command SHALL configure AI coding assistants with OpenSpec instructions based on user selection. #### Scenario: Prompting for AI tool selection - **WHEN** run - **THEN** prompt user to select AI tools to configure: - Claude Code (✅ OpenSpec custom slash commands available) - Cursor (✅ OpenSpec custom slash commands available) - AGENTS.md (works with Codex, Amp, Copilot, …) ### Requirement: AI Tool Configuration Details The command SHALL properly configure selected AI tools with OpenSpec-specific instructions using a marker system. #### Scenario: Configuring Claude Code - **WHEN** Claude Code is selected - **THEN** create or update `CLAUDE.md` in the project root directory (not inside openspec/) #### Scenario: Configuring AGENTS standard - **WHEN** the AGENTS.md standard is selected - **THEN** create or update `AGENTS.md` in the project root directory (not inside openspec/) #### Scenario: Creating new CLAUDE.md - **WHEN** CLAUDE.md does not exist - **THEN** create new file with OpenSpec content wrapped in markers: ```markdown # OpenSpec Project This document provides instructions for AI coding assistants on how to use OpenSpec conventions for spec-driven development. Follow these rules precisely when working on OpenSpec-enabled projects. This project uses OpenSpec for spec-driven development. Specifications are the source of truth. See @openspec/AGENTS.md for detailed conventions and guidelines. ``` #### Scenario: Creating new AGENTS.md - **WHEN** AGENTS.md does not exist in the project root - **THEN** create new file with OpenSpec content wrapped in markers using the same template as CLAUDE.md #### Scenario: Updating existing CLAUDE.md - **WHEN** CLAUDE.md already exists - **THEN** preserve all existing content - **AND** insert OpenSpec content at the beginning of the file using markers - **AND** ensure markers don't duplicate if they already exist #### Scenario: Updating existing AGENTS.md - **WHEN** AGENTS.md already exists in the project root - **THEN** preserve all existing content - **AND** ensure the OpenSpec-managed block at the beginning of the file is refreshed without duplicating markers #### Scenario: Managing content with markers - **WHEN** using the marker system - **THEN** use `` to mark the beginning of managed content - **AND** use `` to mark the end of managed content - **AND** allow OpenSpec to update its content without affecting user customizations - **AND** preserve all content outside the markers intact WHY use markers: - Users may have existing CLAUDE.md or AGENTS.md instructions they want to keep - OpenSpec can update its instructions in future versions - Clear boundary between OpenSpec-managed and user-managed content ================================================ FILE: openspec/changes/archive/2025-09-29-add-agents-md-config/specs/cli-update/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Update Behavior The update command SHALL update OpenSpec instruction files to the latest templates in a team-friendly manner. #### Scenario: Running update command - **WHEN** a user runs `openspec update` - **THEN** the command SHALL: - Check if the `openspec` directory exists - Replace `openspec/AGENTS.md` with the latest template (complete replacement) - Create or refresh a root-level `AGENTS.md` file using the managed marker block (create if missing) - Update **only existing** AI tool configuration files (e.g., CLAUDE.md) - Check each registered AI tool configurator - For each configurator, check if its file exists - Update only files that already exist using their markers - Preserve user content outside markers - Display success message listing updated files ### Requirement: Tool-Agnostic Updates The update command SHALL handle file updates in a predictable and safe manner while respecting team tool choices. #### Scenario: Updating files - **WHEN** updating files - **THEN** completely replace `openspec/AGENTS.md` with the latest template - **AND** create or update the root-level `AGENTS.md` using the OpenSpec markers - **AND** update only the OpenSpec-managed blocks in **existing** AI tool files using markers - **AND** use the default directory name `openspec` - **AND** be idempotent (repeated runs have no additional effect) - **AND** respect team members' AI tool choices by not creating additional tool files beyond the root `AGENTS.md` ### Requirement: Core Files Always Updated The update command SHALL always update the core OpenSpec files and display an ASCII-safe success message. #### Scenario: Successful update - **WHEN** the update completes successfully - **THEN** replace `openspec/AGENTS.md` with the latest template - **AND** ensure the root-level `AGENTS.md` matches the latest template via the marker block - **AND** update existing AI tool configuration files within markers - **AND** display the message: "Updated OpenSpec instructions" ================================================ FILE: openspec/changes/archive/2025-09-29-add-agents-md-config/tasks.md ================================================ # Implementation Tasks ## 1. Extend Init Workflow - [x] 1.1 Add an "AGENTS.md standard" option to the `openspec init` tool-selection prompt, respecting the existing UI conventions. - [x] 1.2 Generate or refresh a root-level `AGENTS.md` file using the OpenSpec markers when that option is selected, sourcing content from the canonical template. ## 2. Enhance Update Command - [x] 2.1 Ensure `openspec update` writes the root `AGENTS.md` from the latest template (creating it if missing) alongside `openspec/AGENTS.md`. - [x] 2.2 Update success messaging and logging to reflect creation vs refresh of the AGENTS standard file. ## 3. Shared Template Handling - [x] 3.1 Refactor template utilities if necessary so both commands reuse the same content without duplication. - [x] 3.2 Add automated tests covering init/update flows for projects with and without an existing `AGENTS.md`, ensuring markers behave correctly. ## 4. Documentation - [x] 4.1 Update CLI specs and user-facing docs to describe AGENTS standard support. - [x] 4.2 Run `openspec validate add-agents-md-config --strict` and document any notable behavior changes. ================================================ FILE: openspec/changes/archive/2025-09-29-add-multi-agent-init/proposal.md ================================================ # Allow Additional AI Tool Initialization After Setup ## Summary - Let `openspec init` configure new AI coding tools for projects that already contain an OpenSpec structure. - Keep the initialization flow safe by skipping structure creation and only generating files for tools the user explicitly selects. - Provide clear feedback so users know which tool files were added versus already present. ## Motivation Today `openspec init` exits with an error once an `openspec/` directory exists. That protects the directory layout, but it blocks teams that start with one assistant (for example, Claude Code) and later want to add another such as Cursor. They have to create those files by hand or rerun `init` in a clean clone, which undermines the "easy onboarding" promise. Letting the command extend an existing installation keeps the workflow consistent and avoids manual file management. ## Proposal 1. Detect an existing OpenSpec structure at the start of `openspec init` and branch into an "extend" mode instead of exiting. - Announce that the base structure already exists and that the command will only manage AI tool configuration files. - Keep the existing guard for directories or files we must not overwrite. 2. Present the usual AI tool selection prompt even in extend mode, showing which tools are already configured. - Skip disabled options that remain "coming soon". - Mark already configured tools as such so users know whether selecting them will refresh or add files. 3. When the user selects additional tools, generate the same initialization files that a fresh run would create (e.g., Cursor workspace files) while leaving untouched tools intact apart from marker-managed sections. - Do nothing when the user selects no new tools and keep the previous error messaging to avoid silently succeeding. 4. Summarize the outcome (created, refreshed, skipped) before exiting with code 0 when work was performed. - Include friendly guidance that future updates to shared content still come from `openspec update`. ## Out of Scope - Changing how `openspec update` discovers or updates AI tool files. - Supporting brand-new AI tools beyond those already wired into the CLI. - Adding non-interactive flags for selecting multiple tools in one run (follow-up if needed). ## Risks & Mitigations - **User confusion about extend mode** → Explicitly log what will happen before prompting and summarise results afterward. - **Accidental overwrites** → Continue using marker-based updates and skip files unless the user chooses that tool. - **Inconsistent state if init fails mid-run** → Reuse existing rollback/transaction logic so partial writes clean up. ================================================ FILE: openspec/changes/archive/2025-09-29-add-multi-agent-init/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Safety Checks The command SHALL perform safety checks to prevent overwriting existing structures and ensure proper permissions. #### Scenario: Detecting existing initialization - **WHEN** the `openspec/` directory already exists - **THEN** inform the user that OpenSpec is already initialized, skip recreating the base structure, and enter an extend mode - **AND** continue to the AI tool selection step so additional tools can be configured - **AND** display the existing-initialization error message only when the user declines to add any AI tools ### Requirement: Interactive Mode The command SHALL provide an interactive menu for AI tool selection with clear navigation instructions. #### Scenario: Displaying interactive menu - **WHEN** run in fresh or extend mode - **THEN** present a looping select menu that lets users toggle tools with Enter and finish via a "Done" option - **AND** label already configured tools with "(already configured)" while keeping disabled options marked "coming soon" - **AND** change the prompt copy in extend mode to "Which AI tools would you like to add or refresh?" - **AND** display inline instructions clarifying that Enter toggles a tool and selecting "Done" confirms the list ## ADDED Requirements ### Requirement: Additional AI Tool Initialization `openspec init` SHALL allow users to add configuration files for new AI coding assistants after the initial setup. #### Scenario: Configuring an extra tool after initial setup - **GIVEN** an `openspec/` directory already exists and at least one AI tool file is present - **WHEN** the user runs `openspec init` and selects a different supported AI tool - **THEN** generate that tool's configuration files with OpenSpec markers the same way as during first-time initialization - **AND** leave existing tool configuration files unchanged except for managed sections that need refreshing - **AND** exit with code 0 and display a success summary highlighting the newly added tool files ### Requirement: Success Output Enhancements `openspec init` SHALL summarize tool actions when initialization or extend mode completes. #### Scenario: Showing tool summary - **WHEN** the command completes successfully - **THEN** display a categorized summary of tools that were created, refreshed, or skipped (including already-configured skips) - **AND** personalize the "Next steps" header using the names of the selected tools, defaulting to a generic label when none remain ### Requirement: Exit Code Adjustments `openspec init` SHALL treat extend mode with no selected tools as a guarded error. #### Scenario: Preventing empty extend runs - **WHEN** OpenSpec is already initialized and the user selects no additional tools - **THEN** exit with code 1 after showing the existing-initialization guidance message ================================================ FILE: openspec/changes/archive/2025-09-29-add-multi-agent-init/tasks.md ================================================ # Implementation Tasks ## 1. Extend Init Guard - [x] 1.1 Detect existing OpenSpec structures at the start of `openspec init` and enter an extend mode instead of failing. - [x] 1.2 Log that core scaffolding will be skipped while still protecting against missing write permissions. ## 2. Update AI Tool Selection - [x] 2.1 Present AI tool choices even in extend mode, indicating which tools are already configured. - [x] 2.2 Ensure disabled "coming soon" tools remain non-selectable. ## 3. Generate Additional Tool Files - [x] 3.1 Create configuration files for newly selected tools while leaving untouched tools unaffected apart from marker-managed sections. - [x] 3.2 Summarize created, refreshed, and skipped tools before exiting with the appropriate code. ## 4. Verification - [x] 4.1 Add tests covering rerunning `openspec init` to add another tool and the scenario where the user declines to add anything. ================================================ FILE: openspec/changes/archive/2025-09-29-add-slash-command-support/proposal.md ================================================ # Add Slash Command Support for Coding Agents ## Summary - Enable OpenSpec to generate and update custom slash commands for supported coding agents (Claude Code and Cursor). - Provide three slash commands aligned with OpenSpec's workflow: proposal (start a change proposal), apply (implement), and archive. - Share slash command templating between agents to make future extensions simple. ## Motivation Developers use different coding agents and editors. Having consistent slash commands across tools for the OpenSpec workflow reduces friction and ensures a standard way to trigger the workflow. Supporting both Claude Code and Cursor now lays a foundation for future agents that introduce slash command features. ## Proposal 1. During `openspec init`, when a user selects a supported tool, generate slash command configuration for three OpenSpec workflow stages: - Claude (namespaced): `/openspec/proposal`, `/openspec/apply`, `/openspec/archive`. - Cursor (flat, prefixed): `/openspec-proposal`, `/openspec-apply`, `/openspec-archive`. - Semantics: - Create – scaffold a change (ID, `proposal.md`, `tasks.md`, delta specs); validate strictly. - Apply – implement an approved change; complete tasks; validate strictly. - Archive – archive after deployment; update specs if needed. - Each command file MUST embed concise, step-by-step instructions sourced from `openspec/README.md` (see Template Content section). 2. Store slash command files per tool: - Claude Code: `.claude/commands/openspec/{proposal,apply,archive}.md` - Cursor: `.cursor/commands/{openspec-proposal,openspec-apply,openspec-archive}.md` - Ensure nested directories are created. 3. Command file format and metadata: - Use Markdown with optional YAML frontmatter for tool metadata (name/title, description, category/tags) when supported by the tool. - Place OpenSpec markers around the body only, never inside frontmatter. - Keep the visible slash name, file name, and any frontmatter `name`/`id` consistently aligned (e.g., `proposal`, `openspec-proposal`). - Namespacing: categorize these under “OpenSpec” and prefer unique IDs (e.g., `openspec-proposal`) to avoid collisions. 4. Centralize templates: define command bodies once and reuse across tools; apply minimal per-tool wrappers (frontmatter, categories, filenames). 5. During `openspec update`, refresh only existing slash command files (per-file basis) within markers; do not create missing files or new tools. ## Design Ideas - Introduce `SlashCommandConfigurator` to manage multiple files per tool. - Expose targets rather than a single `configFileName` (e.g., `getTargets(): Array<{ path: string; kind: 'slash'; id: string }>`). - Provide `generateAll(projectPath, openspecDir)` for init and `updateExisting(projectPath, openspecDir)` for update. - Per-tool adapters add only frontmatter and pathing; bodies come from shared templates. - Templates live in `TemplateManager` with helpers that extract concise, authoritative snippets from `openspec/README.md`. - Update flow logs per-file results so users see exactly which slash files were refreshed. ### Marker Placement - Markers MUST wrap only the Markdown body contents: - Frontmatter (if present) goes first. - Then `` … body … ``. - Avoid inserting markers into the YAML block to prevent parse errors. ### Idempotency and Creation Rules - `init`: create all three files for the chosen tool(s) once; subsequent `init` runs are no-ops for existing files. - `update`: refresh only files that exist; skip missing ones without creating new files. - Directory creation for `.claude/commands/openspec/` and `.cursor/commands/` is the configurator’s responsibility. ### Command Naming & UX - Claude Code: use namespacing in the slash itself for readability and grouping: `/openspec/proposal`, `/openspec/apply`, `/openspec/archive`. - Cursor: use flat names with an `openspec-` prefix: `/openspec-proposal`, `/openspec-apply`, `/openspec-archive`. Group via `category: OpenSpec` when supported. - Consistency: align file names, visible slash names, and any frontmatter `id` (e.g., `id: openspec-apply`). - Migration: do not rename existing commands during `update`; apply new naming only on `init` (or via an explicit migrate step). ## Open Questions - Validate exact metadata/frontmatter supported by each tool version; if unsupported, omit frontmatter and ship Markdown body only. - Confirm the final Cursor command file location for the targeted versions; fall back to Markdown-only if Cursor does not parse frontmatter. - Evaluate additional commands beyond the initial three (e.g., `/show-change`, `/validate-all`) based on user demand. ## Alternatives - Hard-code slash command text per tool (rejected: duplicates content; increases maintenance). - Delay Cursor support until its config stabilizes (partial accept): gate Cursor behind a feature flag until verified in real environments. ## Risks - Tool configuration formats may change, requiring updates to wrappers/frontmatter. - Incorrect paths or categories can hide commands; add path existence checks and clear logging. - Marker misuse (inside frontmatter) can break parsing; enforce placement rules in tests. ## Future Work - Support additional editors/agents that expose slash command APIs. - Allow users to customize command names and categories during `openspec init`. - Provide a dedicated command to regenerate slash commands without running full `update`. ## File Format Examples The following examples illustrate expected structure. If a tool does not support frontmatter, omit the YAML block and keep only the markers + body. ### Claude Code: `.claude/commands/openspec/proposal.md` ```markdown --- name: OpenSpec: Proposal description: Scaffold a new OpenSpec change and validate strictly. category: OpenSpec tags: [openspec, change] --- ...command body from shared template... ``` Slash invocation: `/openspec/proposal` (namespaced) ### Cursor: `.cursor/commands/openspec-proposal.md` ```markdown --- name: /openspec-proposal id: openspec-proposal category: OpenSpec description: Scaffold a new OpenSpec change and validate strictly. --- ...command body from shared template... ``` Slash invocation: `/openspec-proposal` (flat, prefixed) ## Template Content Templates should be brief, actionable, and sourced from `openspec/README.md` to avoid duplication. Each command body includes: - Guardrails: ask 1–2 clarifying questions if needed; follow minimal-complexity rules; use `pnpm` for Node projects. - Step list tailored to the workflow stage (proposal, apply, archive), including strict validation commands. - Pointers to `openspec show`, `openspec list`, and troubleshooting tips when validation fails. ## Testing Strategy - Golden snapshots for generated files per tool (frontmatter + markers + body). - Partial presence tests: if 1–2 files exist, `update` only refreshes those and does not create missing ones. - Marker placement tests: ensure markers never appear inside frontmatter; cover missing/duplicated marker recovery behavior. - Logging tests: `update` reports per-file updates for slash commands. ================================================ FILE: openspec/changes/archive/2025-09-29-add-slash-command-support/specs/cli-init/spec.md ================================================ ## ADDED Requirements ### Requirement: Slash Command Configuration The init command SHALL generate slash command files for supported editors using shared templates. #### Scenario: Generating slash commands for Claude Code - **WHEN** the user selects Claude Code during initialization - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cursor - **WHEN** the user selects Cursor during initialization - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for OpenCode - **WHEN** the user selects OpenCode during initialization - **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage ================================================ FILE: openspec/changes/archive/2025-09-29-add-slash-command-support/specs/cli-update/spec.md ================================================ ## ADDED Requirements ### Requirement: Slash Command Updates The update command SHALL refresh existing slash command files for configured tools without creating new ones. #### Scenario: Updating slash commands for Claude Code - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Cursor - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for OpenCode - **WHEN** `.opencode/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Missing slash command file - **WHEN** a tool lacks a slash command file - **THEN** do not create a new file during update ================================================ FILE: openspec/changes/archive/2025-09-29-add-slash-command-support/tasks.md ================================================ # Implementation Tasks ## 1. Templates and Configurators - [x] 1.1 Create shared templates for the Proposal, Apply, and Archive commands with instructions for each workflow stage from `openspec/README.md`. - [x] 1.2 Implement a `SlashCommandConfigurator` base and tool-specific configurators for Claude Code and Cursor. ## 2. Claude Code Integration - [x] 2.1 Generate `.claude/commands/openspec/{proposal,apply,archive}.md` during `openspec init` using shared templates. - [x] 2.2 Update existing `.claude/commands/openspec/*` files during `openspec update`. ## 3. Cursor Integration - [x] 3.1 Generate `.cursor/commands/{openspec-proposal,openspec-apply,openspec-archive}.md` during `openspec init` using shared templates. - [x] 3.2 Update existing `.cursor/commands/*` files during `openspec update`. ## 4. Verification - [x] 4.1 Add tests verifying slash command files are created and updated correctly. ## 5. OpenCode Integration - [x] 5.1 Generate `.opencode/commands/{openspec-proposal,openspec-apply,openspec-archive}.md` during `openspec init` using shared templates. - [x] 5.2 Update existing `.opencode/commands/*` files during `openspec update`. ================================================ FILE: openspec/changes/archive/2025-09-29-improve-cli-e2e-plan/proposal.md ================================================ ## Why Recent cross-shell regressions for `openspec` commands revealed that our existing unit/integration tests do not exercise the packaged CLI or shell-specific behavior. The prior attempt at Vitest spawn tests stalled because it coupled e2e coverage with `pnpm pack` installs, which fail in network-restricted environments. With those findings incorporated, we now need an approved plan to realign the work. ## What Changes - Adopt a phased strategy that first stabilizes direct spawn testing of the built CLI (`node dist/cli/index.js`) using lightweight fixtures and a shared `runCLI` helper. - Expand coverage once the spawn harness is stable, keeping the initial matrix focused on bash jobs for Linux/macOS and `pwsh` on Windows while exercising both the direct `node dist/cli/index.js` invocation and the bin shim with non-TTY defaults and captured diagnostics. - Treat packaging/install validation as an optional CI safeguard: when a runner has registry access, run a simple pnpm-based pack→install→smoke-test flow; otherwise document it as out of scope while closing remaining hardening items. - Close out the remaining cross-shell hardening items: ensure `.gitattributes` covers packaged assets, enforce executable bits for CLI shims during CI, and finish the pending SIGINT handling improvements. ## Impact - Tests: add `test/cli-e2e` spawn suite, create the shared `runCLI` helper, and adjust `vitest.setup.ts` as needed. - Tooling: update GitHub Actions workflows with the lightweight matrix above and (optionally) a packaging install check where network is available. - Docs: note phase progress and any limitations inline in this proposal (or the relevant spec) so future phases have clear context. ### Phase 1 Status - Shared `test/helpers/run-cli.ts` guarantees the CLI bundle exists before spawning and enforces non-TTY defaults for every invocation. - New `test/cli-e2e/basic.test.ts` covers `--help`, `--version`, a successful `validate --all --json`, and an unknown-item error path against the `tmp-init` fixture copy. - Legacy top-level `validate` exec tests now rely on `runCLI`, avoiding manual `execSync` usage while keeping their fixture authoring intact. - CI matrix groundwork is in place (bash on Linux/macOS, pwsh on Windows) so the spawn suite runs the same way the helper does across supported shells. ================================================ FILE: openspec/changes/archive/2025-09-29-improve-cli-e2e-plan/tasks.md ================================================ ## 1. Phase 1 – Stabilize Local Spawn Coverage - [x] 1.1 Add `test/helpers/run-cli.ts` that ensures the build runs once and executes `node dist/cli/index.js` with non-TTY defaults; update `vitest.setup.ts` to reuse the shared build step. - [x] 1.2 Seed `test/cli-e2e` using the minimal fixture set (`tmp-init` or copy) to cover help/version, a happy-path `validate`, and a representative error flow via the new helper. - [x] 1.3 Migrate the highest-value existing CLI exec tests (e.g., validate) onto `runCLI` and summarize Phase 1 coverage in this proposal for the next phase. ## 2. Phase 2 – Expand Cross-Shell Validation - [x] 2.1 Exercise both entry points (`node dist/cli/index.js`, `bin/openspec.js`) in the spawn suite and add diagnostics for shell/OS context. - [x] 2.2 Extend GitHub Actions to run the spawn suite on bash jobs for Linux/macOS and a `pwsh` job on Windows; capture shell/OS diagnostics and note follow-ups for additional shells. ================================================ FILE: openspec/changes/archive/2025-09-29-improve-deterministic-tests/proposal.md ================================================ # Change: Improve Deterministic Tests (Isolate From Repo State) ## Problem Some unit tests (e.g., ChangeCommand.show/validate) read the live repository state via `process.cwd()` and `openspec/changes`. This makes outcomes depend on whatever directories happen to exist and the order returned by `fs.readdir`, causing flaky success/failure across environments. Symptoms observed: - Tests sometimes select a partial or unrelated change folder. - Failures like missing `proposal.md` when a stray change directory is picked. - Environment/sandbox differences alter `readdir` ordering and worker behavior. ## Goals - Make tests deterministic and hermetic. - Remove dependence on real repo contents and directory ordering. - Keep runtime behavior unchanged for end users. ## Non‑Goals - Introduce heavy frameworks or test harness complexity. - Redesign CLI behavior or change default paths for users. ## Approach 1) Test-local fixture root - Each suite that touches filesystem discovery creates a temporary directory: - `openspec/changes/sample-change/proposal.md` - `openspec/changes/sample-change/specs/sample/spec.md` - `beforeAll`: `process.chdir(tmpRoot)`; `afterAll`: restore original cwd. - Use a constant `changeName = 'sample-change'`; remove reliance on `readdir` order. 2) Optional thin DI for commands (minimal, if needed) - Allow `ChangeCommand` (and similar) to accept an optional `root` path (default `process.cwd()`), used for path resolution. - Tests pass the temp root explicitly; production code remains unchanged. 3) Harden discovery helpers (safe enhancement) - Update `getActiveChangeIds()`/`getActiveChanges()` to include only directories containing `proposal.md` (and optionally at least one `specs/*/spec.md`). - Prevents incomplete/stray change folders from being treated as active. ## Rationale - Small, focused changes eliminate flakiness without altering user workflows. - Temporary fixtures are a well-understood testing pattern and keep tests fast. - Optional constructor root param is a minimal DI surface that avoids global stubbing and keeps code simple. ## Risks & Mitigations - Risk: Tests forget to restore `process.cwd()`. - Mitigation: Add `afterAll` guard restoring cwd; reset `process.exitCode` in `afterEach` where modified. - Risk: Behavior divergence if DI root is misused. - Mitigation: Default to `process.cwd()`; only tests pass custom roots. ## Acceptance Criteria - Tests that previously depended on repo state now: - Create and use a temp fixture root. - Do not read real `openspec/changes` during execution. - Pass consistently regardless of directory order or stray folders. - No change to CLI behavior for end users (paths still default to cwd). ## Rollout - Phase 1: Convert the suites that hit `ChangeCommand.show/validate` to isolated fixtures; verify stability locally and in CI. - Phase 2: Apply the same pattern to any remaining suites that touch file discovery (`list`, `show`, `validate`, `diff`). - Phase 3 (optional): Introduce the constructor `root` param and discovery hardening, if Phase 1 alone isn’t sufficient. ================================================ FILE: openspec/changes/archive/2025-09-29-improve-deterministic-tests/tasks.md ================================================ # Implementation Tasks ## 1. Test Isolation - [x] 1.1 Create temp fixture roots per suite (openspec/changes, openspec/specs) - [x] 1.2 Use process.chdir to temp root within tests - [x] 1.3 Restore original cwd and clean temp dirs after each ## 2. Deterministic Discovery - [x] 2.1 Implement getActiveChangeIds(root?) to only include dirs with proposal.md - [x] 2.2 Implement getSpecIds(root?) to only include dirs with spec.md - [x] 2.3 Return sorted results to avoid fs.readdir ordering variance ## 3. Command Integration - [x] 3.1 Ensure change/show/validate rely on cwd and discovery helpers - [x] 3.2 Keep runtime behavior unchanged for end users ## 4. Validation - [x] 4.1 Convert affected command tests (show, spec, validate, change) to isolated fixtures - [x] 4.2 Verify tests pass consistently across environments - [x] 4.3 Confirm no reads from real repo state during tests ## 5. Optional (Not Needed Now) - [x] 5.1 Add optional root param to discovery helpers (default process.cwd()) ================================================ FILE: openspec/changes/archive/2025-09-29-improve-init-onboarding/proposal.md ================================================ ## Why The current `openspec init` flow assumes a single assistant selection and stops once an OpenSpec structure already exists. That makes onboarding feel rigid: teams cannot configure multiple tools in one pass, they do not learn which files were refreshed, and the success copy always references Claude even when other assistants are involved. ## What Changes - Allow selecting multiple assistants during `openspec init`, including refreshing existing configurations in a single run. - Provide richer onboarding copy that summarizes which tool files were created or refreshed and guides users on next steps for each assistant. - Align generated AI-instruction content and specs so CLAUDE.md and AGENTS.md share the same OpenSpec guidance. - Update specs and tests to cover the multi-select prompt, improved summaries, and extend-mode coordination. ## Impact - Specs: `cli-init` - Code: `src/core/init.ts`, `src/core/config.ts`, `src/core/templates/*`, `src/core/configurators/*` - Tests: `test/core/init.test.ts`, `test/core/update.test.ts` ================================================ FILE: openspec/changes/archive/2025-09-29-improve-init-onboarding/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: AI Tool Configuration The command SHALL configure AI coding assistants with OpenSpec instructions based on user selection. #### Scenario: Prompting for AI tool selection - **WHEN** run interactively - **THEN** prompt the user with "Which AI tools do you use?" using a multi-select menu - **AND** list every available tool with a checkbox: - Claude Code (creates or refreshes CLAUDE.md and slash commands) - Cursor (creates or refreshes `.cursor/commands/*` slash commands) - AGENTS.md standard (creates or refreshes AGENTS.md with OpenSpec markers) - **AND** show "(already configured)" beside tools whose managed files exist so users understand selections will refresh content - **AND** treat disabled tools as "coming soon" and keep them unselectable - **AND** allow confirming with Enter after selecting one or more tools ### Requirement: AI Tool Configuration Details The command SHALL properly configure selected AI tools with OpenSpec-specific instructions using a marker system. #### Scenario: Configuring Claude Code - **WHEN** Claude Code is selected - **THEN** create or update `CLAUDE.md` in the project root directory (not inside openspec/) #### Scenario: Creating new CLAUDE.md - **WHEN** CLAUDE.md does not exist - **THEN** create new file with OpenSpec content wrapped in markers: ```markdown # OpenSpec Instructions Instructions for AI coding assistants using OpenSpec for spec-driven development. ## TL;DR Quick Checklist - Search existing work: `openspec spec list --long`, `openspec list` - Decide scope: new capability vs modify existing capability - Pick a unique `change-id`: verb-led kebab-case (`add-`, `update-`, `remove-`, `refactor-`) - Scaffold: `proposal.md`, `tasks.md`, optional `design.md`, and spec deltas - Validate with `openspec validate [change-id] --strict` - Request approval before implementation ``` #### Scenario: Updating existing CLAUDE.md - **WHEN** CLAUDE.md already exists - **THEN** preserve all existing content - **AND** insert OpenSpec content at the beginning of the file using markers - **AND** ensure markers don't duplicate if they already exist #### Scenario: Managing content with markers - **WHEN** using the marker system - **THEN** use `` to mark the beginning of managed content - **AND** use `` to mark the end of managed content - **AND** allow OpenSpec to update its content without affecting user customizations - **AND** preserve all content outside the markers intact ### Requirement: Interactive Mode The command SHALL provide an interactive menu for AI tool selection with clear navigation instructions. #### Scenario: Displaying interactive menu - **WHEN** run - **THEN** prompt the user with: "Which AI tools do you use?" - **AND** show a checkbox-based multi-select menu with available tools (Claude Code, Cursor, AGENTS.md standard) - **AND** show disabled options as "coming soon" (not selectable) - **AND** display inline help indicating Space toggles selections and Enter confirms #### Scenario: Navigating the menu - **WHEN** the user is in the menu - **THEN** allow arrow keys to move between options - **AND** allow Spacebar to toggle the highlighted option - **AND** allow Enter key to confirm all current selections ### Requirement: Success Output The command SHALL provide clear, actionable next steps upon successful initialization. #### Scenario: Displaying success message - **WHEN** initialization completes successfully - **THEN** display a success banner followed by actionable prompts tailored to the selected tools - **AND** summarize which assistant files were created versus refreshed (e.g., `CLAUDE.md (created)`, `.cursor/commands/openspec-apply.md (refreshed)`) - **AND** include copy-pasteable onboarding prompts for each configured assistant, replacing placeholder text ([YOUR FEATURE HERE]) with real guidance to customize - **AND** reference AGENTS.md-compatible assistants when no tool-specific file exists (e.g., when only AGENTS.md standard is selected) ================================================ FILE: openspec/changes/archive/2025-09-29-improve-init-onboarding/tasks.md ================================================ ## 1. Planning & Spec Updates - [x] 1.1 Confirm overlap with `add-multi-agent-init` and coordinate extend-mode flow - [x] 1.2 Update `openspec/specs/cli-init/spec.md` to capture multi-select onboarding requirements ## 2. Implementation - [x] 2.1 Add multi-select support to the `openspec init` prompt, including indicators for existing tool configs - [x] 2.2 Enhance success messaging to summarize created/refreshed assets per tool - [x] 2.3 Ensure shared instruction template is applied consistently (CLAUDE.md, AGENTS.md, slash commands) ## 3. Quality - [x] 3.1 Expand unit tests for init/update flows covering multi-select and summaries - [x] 3.2 Perform `openspec init` smoke test in a temp directory (document output) ================================================ FILE: openspec/changes/archive/2025-09-29-remove-diff-command/proposal.md ================================================ # Remove Diff Command ## Problem The `openspec diff` command adds unnecessary complexity to the OpenSpec CLI for several reasons: 1. **Redundant functionality**: The `openspec show` command already provides comprehensive visualization of changes through structured JSON output and markdown rendering 2. **Maintenance burden**: The diff command requires a separate dependency (jest-diff) and additional code complexity (~227 lines) 3. **Limited value**: Developers can achieve better diff visualization using existing tools: - Git diff for actual file changes - The `show` command for structured change viewing - Standard diff utilities for comparing spec files directly 4. **Inconsistent with verb-noun pattern**: The command doesn't follow the preferred verb-first command structure that other commands are migrating to ## Solution Remove the `openspec diff` command entirely and guide users to more appropriate alternatives: 1. **For viewing change content**: Use `openspec show ` which provides: - Structured JSON output with `--json` flag - Markdown rendering for human-readable format - Delta-only views with `--deltas-only` flag - Full spec content visualization 2. **For comparing files**: Use standard tools: - `git diff` for version control comparisons - System diff utilities for file-by-file comparisons - IDE diff viewers for visual comparisons ## Benefits - **Reduced complexity**: Removes ~227 lines of code and the jest-diff dependency - **Clearer user journey**: Directs users to the canonical `show` command for viewing changes - **Lower maintenance**: Fewer commands to maintain and test - **Better alignment**: Focuses on the core OpenSpec workflow without redundant features ## Implementation ### Files to Remove - `/src/core/diff.ts` - The entire diff command implementation - `/openspec/specs/cli-diff/spec.md` - The diff command specification ### Files to Update - `/src/cli/index.ts` - Remove diff command registration (lines 8, 84-96) - `/package.json` - Remove jest-diff dependency - `/README.md` - Remove diff command documentation - `/openspec/README.md` - Remove diff command references - Various documentation files mentioning `openspec diff` ### Migration Guide for Users Users currently using `openspec diff` should transition to: ```bash # Before openspec diff add-feature # After - view the change proposal openspec show add-feature # After - view only the deltas openspec show add-feature --json --deltas-only # After - use git for file comparisons git diff openspec/specs openspec/changes/add-feature/specs ``` ## Risks - **User disruption**: Existing users may have workflows depending on the diff command - Mitigation: Provide clear migration guide and deprecation period - **Loss of visual diff**: The colored, unified diff format will no longer be available - Mitigation: Users can use git diff or other tools for visual comparisons ## Success Metrics - Successful removal with no broken dependencies - Documentation updated to reflect the change - Tests passing without the diff command - Reduced package size from removing jest-diff dependency ================================================ FILE: openspec/changes/archive/2025-09-29-remove-diff-command/tasks.md ================================================ # Remove Diff Command - Tasks ## 1. Remove Core Implementation - [x] Delete `/src/core/diff.ts` - [x] Remove DiffCommand import from `/src/cli/index.ts` - [x] Remove diff command registration from CLI ## 2. Remove Specifications - [x] Delete `/openspec/specs/cli-diff/spec.md` - [x] Archive the spec for historical reference if needed ## 3. Update Dependencies - [x] Remove jest-diff from package.json dependencies - [x] Run pnpm install to update lock file ## 4. Update Documentation - [x] Update main README.md to remove diff command references - [x] Update openspec/README.md to remove diff command from command list - [x] Update CLAUDE.md template if it mentions diff command - [x] Update any example workflows that use diff command ## 5. Update Related Files - [x] Search and update any remaining references to "openspec diff" in: - Template files - Test files (if any exist for diff command) - Archive documentation - Change proposals ## 7. Testing - [x] Ensure all tests pass after removal - [x] Verify CLI help text no longer shows diff command - [x] Test that show command provides adequate replacement functionality ## 8. Documentation of Alternative Workflows - [x] Document how to use `openspec show` for viewing changes - [x] Document how to use git diff for file comparisons - [x] Add migration guide to help text or documentation ================================================ FILE: openspec/changes/archive/2025-09-29-sort-active-changes-by-progress/proposal.md ================================================ # Change: Sort Active Changes by Progress ## Problem - The dashboard currently lists active changes in filesystem discovery order. - Users cannot quickly spot proposals that have not started or are nearly complete. - Inconsistent ordering between runs makes it harder to track progress when many changes exist. ## Proposal 1. Update the Active Changes list in the dashboard to sort by percentage of completion in ascending order so 0% items show first. 2. When two changes share the same completion percentage, break ties deterministically by change identifier (alphabetical). ## Benefits - Highlights work that has not started yet, enabling quicker prioritization. - Provides consistent ordering across machines and repeated runs. - Keeps the dashboard compact while communicating the most important status signal. ## Risks & Mitigations - **Risk:** Sorting logic could regress rendering when progress data is missing. - **Mitigation:** Treat missing progress as 0% so items still surface and document behavior in tests. - **Risk:** Additional sorting could impact performance for large change sets. - **Mitigation:** The number of active changes is typically small; sorting a few entries is negligible. ## Success Criteria - Dashboard output shows active changes ordered by ascending completion percentage with deterministic tie-breaking. - Unit coverage verifying the sort when percentages vary and when ties occur. ================================================ FILE: openspec/changes/archive/2025-09-29-sort-active-changes-by-progress/specs/cli-view/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Active Changes Display The dashboard SHALL show active changes with visual progress indicators. #### Scenario: Active changes ordered by completion percentage - **WHEN** multiple active changes are displayed with progress information - **THEN** list them sorted by completion percentage ascending so 0% items appear first - **AND** treat missing progress values as 0% for ordering - **AND** break ties by change identifier in ascending alphabetical order to keep output deterministic ================================================ FILE: openspec/changes/archive/2025-09-29-sort-active-changes-by-progress/tasks.md ================================================ # Implementation Tasks ## 1. Dashboard Sorting Logic - [x] 1.1 Update the Active Changes rendering to sort by completion percentage ascending. - [x] 1.2 Treat missing progress as 0% and break ties alphabetically by change identifier. ## 2. Verification - [x] 2.1 Add tests that cover different completion percentages and tie cases to confirm deterministic ordering. ================================================ FILE: openspec/changes/archive/2025-09-29-update-agent-file-name/proposal.md ================================================ # Update Agent Instruction File Name ## Problem The agent instructions live in `openspec/README.md`, which clashes with conventional project README usage and creates confusion for tooling and contributors. ## Solution Rename the agent instruction file to `openspec/AGENTS.md` and update OpenSpec tooling to use the new filename: - `openspec init` generates `AGENTS.md` instead of `README.md` - Templates and code reference `AGENTS.md` - Specifications and documentation are updated accordingly ## Benefits - Clear separation from project documentation - Consistent naming with other agent instruction files - Simplifies tooling and project onboarding ## Implementation - Rename instruction file and template - Update CLI commands (`init`, `update`) to read/write `AGENTS.md` - Adjust specs and documentation to reference the new path ## Risks - Existing projects may still rely on `README.md` - Tooling may miss lingering references to the old filename ## Success Metrics - `openspec init` creates `openspec/AGENTS.md` - `openspec update` refreshes `AGENTS.md` - All specs reference `openspec/AGENTS.md` ================================================ FILE: openspec/changes/archive/2025-09-29-update-agent-file-name/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Directory Creation The command SHALL create the complete OpenSpec directory structure with all required directories and files. #### Scenario: Creating OpenSpec structure - **WHEN** `openspec init` is executed - **THEN** create the following directory structure: ``` openspec/ ├── project.md ├── AGENTS.md ├── specs/ └── changes/ └── archive/ ``` ### Requirement: File Generation The command SHALL generate required template files with appropriate content for immediate use. #### Scenario: Generating template files - **WHEN** initializing OpenSpec - **THEN** generate `AGENTS.md` containing complete OpenSpec instructions for AI assistants - **AND** generate `project.md` with project context template ### Requirement: AI Tool Configuration Details The command SHALL properly configure selected AI tools with OpenSpec-specific instructions using a marker system. #### Scenario: Creating new CLAUDE.md - **WHEN** CLAUDE.md does not exist - **THEN** create new file with OpenSpec content wrapped in markers including reference to `@openspec/AGENTS.md` ### Requirement: Success Output The command SHALL provide clear, actionable next steps upon successful initialization. #### Scenario: Displaying success message - **WHEN** initialization completes successfully - **THEN** include prompt: "Please explain the OpenSpec workflow from openspec/AGENTS.md and how I should work with you on this project" ================================================ FILE: openspec/changes/archive/2025-09-29-update-agent-file-name/specs/cli-update/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Update Behavior The update command SHALL update OpenSpec instruction files to the latest templates in a team-friendly manner. #### Scenario: Running update command - **WHEN** a user runs `openspec update` - **THEN** replace `openspec/AGENTS.md` with the latest template ### Requirement: File Handling The update command SHALL handle file updates in a predictable and safe manner. #### Scenario: Updating files - **WHEN** updating files - **THEN** completely replace `openspec/AGENTS.md` with the latest template ### Requirement: Core Files Always Updated The update command SHALL always update the core OpenSpec files and display an ASCII-safe success message. #### Scenario: Successful update - **WHEN** the update completes successfully - **THEN** replace `openspec/AGENTS.md` with the latest template ================================================ FILE: openspec/changes/archive/2025-09-29-update-agent-file-name/specs/openspec-conventions/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Project Structure An OpenSpec project SHALL maintain a consistent directory structure for specifications and changes. #### Scenario: Initializing project structure - **WHEN** an OpenSpec project is initialized - **THEN** it SHALL have this structure: ``` openspec/ ├── project.md # Project-specific context ├── AGENTS.md # AI assistant instructions ├── specs/ # Current deployed capabilities │ └── [capability]/ # Single, focused capability │ ├── spec.md # WHAT and WHY │ └── design.md # HOW (optional, for established patterns) └── changes/ # Proposed changes ├── [change-name]/ # Descriptive change identifier │ ├── proposal.md # Why, what, and impact │ ├── tasks.md # Implementation checklist │ ├── design.md # Technical decisions (optional) │ └── specs/ # Complete future state │ └── [capability]/ │ └── spec.md # Clean markdown (no diff syntax) └── archive/ # Completed changes └── YYYY-MM-DD-[name]/ ``` ================================================ FILE: openspec/changes/archive/2025-09-29-update-agent-file-name/tasks.md ================================================ # Update Agent Instruction File Name - Tasks ## 1. Rename Instruction File - [x] Rename `openspec/README.md` to `openspec/AGENTS.md` - [x] Update root references to new path ## 2. Update Templates - [x] Rename `src/core/templates/readme-template.ts` to `agents-template.ts` - [x] Update exported constant from `readmeTemplate` to `agentsTemplate` ## 3. Adjust CLI Commands - [x] Modify `openspec init` to generate `AGENTS.md` - [x] Update `openspec update` to refresh `AGENTS.md` - [x] Ensure CLAUDE.md markers link to `@openspec/AGENTS.md` ## 4. Update Specifications - [x] Modify `cli-init` spec to reference `AGENTS.md` - [x] Modify `cli-update` spec to reference `AGENTS.md` - [x] Modify `openspec-conventions` spec to include `AGENTS.md` in project structure ## 5. Validation - [x] `pnpm test` ================================================ FILE: openspec/changes/archive/2025-09-29-update-agent-instructions/design.md ================================================ # Design: Agent Instructions Update ## Approach ### Information Architecture - **Front-load critical information** - Three-stage workflow comes first - **Clear hierarchy** - Core Workflow → Quick Start → Commands → Details → Edge Cases - **50% length reduction** - Target ~285 lines from current ~575 lines - **Imperative mood** - "Create proposal" vs "You should create a proposal" - **Bullet points over paragraphs** - Scannable, concise information ### Three-Stage Workflow Documentation The workflow is now prominently featured as a core concept: 1. **Creating** - Proposal generation phase 2. **Implementing** - Code development phase with explicit steps: - Read proposal.md for understanding - Read design.md for technical context - Read tasks.md for checklist - Implement tasks sequentially - Mark complete immediately after each task 3. **Archiving** - Post-deployment finalization phase This structure helps agents understand the lifecycle and their role at each stage. The implementation phase is particularly detailed to prevent common mistakes like skipping documentation or batching task completion. ### CLI Documentation Updates - **Comprehensive command coverage** - All 9 primary commands documented - **`openspec list` prominence** - Essential for discovering changes and specs - **Interactive mode documentation** - How agents can use prompts effectively - **Complete flag documentation** - All options like --json, --type, --skip-specs - **Deprecation cleanup** - Remove noun-first patterns (openspec change show) ### Agent-Specific Enhancements Based on industry best practices for coding agents (Claude Code, Cursor, etc.): **Implementation Workflow** - Explicit steps prevent skipping critical context - Reading proposal/design first ensures understanding before coding - Sequential task completion maintains focus - Immediate marking prevents losing track of progress - Addresses common failure mode: jumping straight to code **Spec Discovery Workflow** - Always check existing specs before creating new ones - Use `openspec list --specs` to discover current capabilities - Prefer modifying existing specs over creating duplicates - Prevents fragmentation and maintains coherent architecture **Decision Clarity** - Clear decision trees eliminating ambiguous conditions - Concrete examples for each decision branch - Simplified bug vs feature determination **Tool Usage Guidance** - Tool selection matrix (when to use Grep vs Glob vs Read) - Error recovery patterns for common failures - Verification workflows to confirm correctness **Context Management** - "Before Any Task" checklist for gathering context - What to read before starting any work - How to maintain state across interactions **Spec File Structure Documentation** - Complete examples with ADDED/MODIFIED/REMOVED sections - Critical scenario formatting (#### Scenario: headers) - Delta file location clarity (changes/{name}/specs/) - Addresses most common creation errors from retrospective **Troubleshooting and Debugging** - Common error messages with solutions - Delta detection debugging steps - Validation best practices - JSON output for inspection - Prevents hours of frustration from silent failures **Best Practices** - Be concise (one-line answers when appropriate) - Be specific (file.ts:42 line references) - Start simple (<100 lines, single-file defaults) - Justify complexity (require metrics/data) ## Design Rationale ### Why These Changes Matter **Cognitive Load Reduction** - Agents process instructions better with clear structure - Front-loading critical info reduces scanning time - Decision trees eliminate analysis paralysis **Industry Alignment** - Follows patterns proven effective in Claude Code, Cursor, GitHub Copilot - Addresses common failure modes (ambiguous decisions, missing context) - Optimizes for LLM strengths (pattern matching) vs weaknesses (calculations) **Addressing Critical Pain Points (from Retrospective)** - **Scenario formatting** - Biggest struggle, now explicitly documented with examples - **Complete spec structure** - Full examples prevent structural errors - **Delta detection issues** - Debugging commands help diagnose problems - **Silent parsing failures** - Troubleshooting section explains common issues **Practical Impact** - Faster agent comprehension of tasks - Fewer misinterpretations of requirements - More consistent implementation quality - Better error recovery when things go wrong - Prevents the most common errors identified in user experience ## Trade-offs ### What We're Removing - Lengthy explanations of concepts that can be inferred - Redundant examples that don't add clarity - Verbose edge case documentation (moved to reference section) - Deprecated command documentation ### What We're Keeping - All critical workflow steps - Complete CLI command reference - Complexity management principles - Directory structure visualization - Quick reference summary ## Implementation Notes The CLAUDE.md template is intentionally more concise than README.md since: - It appears in every project root - Agents can reference the full README.md for details - It needs to load quickly in AI context windows - Focus is on immediate actionable guidance ================================================ FILE: openspec/changes/archive/2025-09-29-update-agent-instructions/proposal.md ================================================ # Update OpenSpec Agent Instructions ## Why The current OpenSpec agent instructions need updates to follow best practices for AI assistant instructions (brevity, clarity, removing ambiguity), ensure CLI commands are current with the actual implementation, and properly document the three-stage workflow pattern that agents should follow. ## What Changes ### Core Structure Improvements - **Front-load the 3-stage workflow** as the primary mental model: 1. Creating a change proposal (proposal.md, spec deltas, design.md, tasks.md) 2. Implementing a change proposal: - First read proposal.md to understand the change - Read design.md if it exists for technical context - Read tasks.md for the implementation checklist - Complete tasks one by one - Mark each task complete immediately after finishing 3. Archiving the change proposal (using archive command after deployment) - **Reduce instruction length by 50%** while maintaining all critical information - **Restructure with clear hierarchy**: Core Workflow → Quick Start → Commands → Details → Edge Cases ### Decision Clarity Enhancements - **Add clear decision trees** for common scenarios (bug vs feature, proposal needed vs not) - **Remove ambiguous conditions** that confuse agent decision-making - **Add "Before Any Task" checklist** for context gathering - **Add "Before Creating Specs" rule** - Always check existing specs first to avoid duplicates ### CLI Documentation Updates - **Complete command documentation** with all current functionality: - `openspec init [path]` - Initialize OpenSpec in a project - `openspec list` - List all active changes (default) - `openspec list --specs` - List all specifications - `openspec show [item]` - Display change or spec with auto-detection - `openspec show` - Interactive mode for selection - `openspec diff [change]` - Show spec differences for a change - `openspec validate [item]` - Validate changes or specs - `openspec archive [change]` - Archive completed change after deployment - `openspec update [path]` - Update OpenSpec instruction files - **Document all flags and options**: - `--json` output format for programmatic use - `--type change|spec` for disambiguation - `--skip-specs` for tooling-only archives - `--strict` for strict validation mode - `--no-interactive` to disable prompts - **Remove deprecated command references** (noun-first patterns like `openspec change show`) - **Add concrete examples** for each command variation - **Document debugging commands**: - `openspec show [change] --json --deltas-only` for inspecting deltas - `openspec validate [change] --strict` for comprehensive validation ### Spec File Structure Documentation - **Complete spec file examples** showing proper structure: ```markdown ## ADDED Requirements ### Requirement: Clear requirement statement The system SHALL provide the functionality... #### Scenario: Descriptive scenario name - **WHEN** condition occurs - **THEN** expected outcome - **AND** additional outcomes ``` - **Scenario formatting requirements** (critical - most common error): - MUST use `#### Scenario:` headers (4 hashtags) - NOT bullet lists or bold text - Each requirement MUST have at least one scenario - **Delta file location** - Clear explanation: - Spec files go in `changes/{name}/specs/` directory - Deltas are automatically extracted from these files - Use operation prefixes: ADDED, MODIFIED, REMOVED, RENAMED ### Troubleshooting Section - **Common errors and solutions**: - "Change must have at least one delta" → Check specs/ directory exists with .md files - "Requirement must have at least one scenario" → Check scenario uses `#### Scenario:` format - Silent scenario parsing failures → Verify exact header format - **Delta detection debugging**: - Use `openspec show [change] --json --deltas-only` to inspect parsed deltas - Check that spec files have operation prefixes (## ADDED Requirements) - Verify specs/ subdirectory structure - **Validation best practices**: - Always use `--strict` flag for comprehensive checks - Use JSON output for debugging: `--json | jq '.deltas'` ### Agent-Specific Improvements - **Implementation workflow** - Clear step-by-step process: 1. Read proposal.md to understand what's being built 2. Read design.md (if exists) for technical decisions 3. Read tasks.md for the implementation checklist 4. Implement tasks one by one in order 5. Mark each task complete immediately: `- [x] Task completed` 6. Never skip ahead or batch task completion - **Spec discovery workflow** - Always check existing specs before creating new ones: - Use `openspec list --specs` to see all current specs - Check if capability already exists before creating - Prefer modifying existing specs over creating duplicates - **Tool selection matrix** - When to use Grep vs Glob vs Read - **Error recovery patterns** - How to handle common failures - **Context management guide** - What to read before starting tasks - **Verification workflows** - How to confirm changes are correct ### Best Practices Section - **Be concise** - One-line answers when appropriate - **Be specific** - Use exact file paths and line numbers (file.ts:42) - **Start simple** - Default to <100 lines, single-file implementations - **Justify complexity** - Require data/metrics for any optimization ## Impact - Affected specs: None (this is a tooling/documentation change) - Affected code: - `src/core/templates/claude-template.ts` - Update CLAUDE.md template - Affected documentation: - `openspec/README.md` - Main OpenSpec instructions - CLAUDE.md files generated by `openspec init` command Note: This is a tooling/infrastructure change that doesn't require spec updates. When archiving, use `openspec archive update-agent-instructions --skip-specs`. ================================================ FILE: openspec/changes/archive/2025-09-29-update-agent-instructions/tasks.md ================================================ # Implementation Tasks ## 1. Restructure OpenSpec README.md - [x] 1.1 Front-load the three-stage workflow as primary content - [x] 1.2 Restructure with hierarchy: Core Workflow → Quick Start → Commands → Details → Edge Cases - [x] 1.3 Reduce total length by 50% (target: ~285 lines from current ~575) - [x] 1.4 Add "Before Any Task" context-gathering checklist - [x] 1.5 Add "Before Creating Specs" rule to check existing specs first ## 2. Add Decision Clarity - [x] 2.1 Create clear decision trees for "Create Proposal?" scenarios - [x] 2.2 Remove ambiguous conditions that confuse agents - [x] 2.3 Add concrete examples for each decision branch - [x] 2.4 Simplify bug vs feature determination logic - [x] 2.5 Add explicit Stage 2 implementation steps (read → implement → mark complete) ## 3. Update CLI Documentation - [x] 3.1 Document `openspec list` and `openspec list --specs` commands - [x] 3.2 Document `openspec show` with all flags and interactive mode - [x] 3.3 Document `openspec diff [change]` for viewing spec differences - [x] 3.4 Document `openspec archive` with --skip-specs option - [x] 3.5 Document `openspec validate` with --strict and batch modes - [x] 3.6 Document `openspec init` and `openspec update` commands - [x] 3.7 Remove all deprecated noun-first command references - [x] 3.8 Add concrete usage examples for each command variation - [x] 3.9 Document all flags: --json, --type, --no-interactive, etc. - [x] 3.10 Document debugging commands: `show --json --deltas-only` ## 4. Add Spec File Documentation - [x] 4.1 Add complete spec file structure example with ADDED/MODIFIED sections - [x] 4.2 Document scenario formatting requirements (#### Scenario: headers) - [x] 4.3 Explain delta file location (changes/{name}/specs/ directory) - [x] 4.4 Show how deltas are automatically extracted - [x] 4.5 Include warning about most common error (scenario formatting) ## 5. Add Troubleshooting Section - [x] 5.1 Document common errors and their solutions - [x] 5.2 Add delta detection debugging steps - [x] 5.3 Include validation best practices (--strict flag) - [x] 5.4 Show how to use JSON output for debugging - [x] 5.5 Add examples of silent parsing failures ## 6. Add Agent-Specific Sections - [x] 6.1 Add implementation workflow (read docs → implement tasks → mark complete) - [x] 6.2 Add spec discovery workflow (check existing before creating) - [x] 6.3 Create tool selection matrix (Grep vs Glob vs Read) - [x] 6.4 Add error recovery patterns section - [x] 6.5 Add context management guide - [x] 6.6 Add verification workflows section - [x] 6.7 Add best practices section (concise, specific, simple) ## 7. Update CLAUDE.md Template - [x] 7.1 Update `src/core/templates/claude-template.ts` with streamlined content - [x] 7.2 Include three-stage workflow prominently - [x] 7.3 Add comprehensive CLI quick reference (list, show, diff, archive, etc.) - [x] 7.4 Add "Before Any Task" checklist - [x] 7.5 Add "Before Creating Specs" rule - [x] 7.6 Keep complexity management principles - [x] 7.7 Add critical scenario formatting note (#### Scenario: headers) - [x] 7.8 Include debugging command reference ## 8. Testing and Validation - [x] 8.1 Test all documented CLI commands for accuracy - [x] 8.2 Run `openspec init` to verify CLAUDE.md generation - [x] 8.3 Validate instruction clarity with example scenarios - [x] 8.4 Ensure no critical information was lost in streamlining - [x] 8.5 Verify decision trees eliminate ambiguity - [x] 8.6 Test scenario formatting examples work correctly - [x] 8.7 Verify troubleshooting steps resolve common errors ================================================ FILE: openspec/changes/archive/2025-09-29-update-markdown-parser-crlf/proposal.md ================================================ # Update Markdown Parser CRLF Handling ## Problem Windows users report that `openspec validate` raises “Change must have a Why section” even when the section exists (see GitHub issue #77). The CLI currently splits markdown on `\n` and compares headers without stripping `\r`, so files saved with CRLF line endings keep a trailing carriage return in the header token. As a result the parser fails to detect `## Why`/`## What Changes`, triggering false validation errors and breaking the workflow on Windows-default editors. ## Solution - Normalize markdown content inside the parser so CRLF and lone-CR inputs are treated as `\n` before section detection, trimming any carriage returns from titles and content comparisons. - Reuse the normalized reader everywhere `MarkdownParser` is constructed to keep behavior consistent for validation, view, spec, and list flows. - Add regression coverage that reproduces the failure (unit test around `parseChange` and a CLI spawn/e2e test that writes a CRLF change then runs `openspec validate`). - Update the `cli-validate` spec to codify the expectation that required sections are recognized regardless of line-ending style. ## Benefits - Restores correct validation behavior for Windows editors without requiring manual line-ending conversion. - Locks in the fix with targeted tests so future parser refactors keep cross-platform support. - Clarifies the spec so downstream work (e.g., cross-shell e2e plan) understands the non-negotiable behavior. ## Risks - Low: parser normalization touches shared code paths that parse specs and changes; need to ensure no regressions in other command consumers (mitigated by existing parser tests plus the new CRLF fixtures). ================================================ FILE: openspec/changes/archive/2025-09-29-update-markdown-parser-crlf/specs/cli-validate/spec.md ================================================ ## ADDED Requirements ### Requirement: Parser SHALL handle cross-platform line endings The markdown parser SHALL correctly identify sections regardless of line ending format (LF, CRLF, CR). #### Scenario: Required sections parsed with CRLF line endings - **GIVEN** a change proposal markdown saved with CRLF line endings - **AND** the document contains `## Why` and `## What Changes` - **WHEN** running `openspec validate ` - **THEN** validation SHALL recognize the sections and NOT raise parsing errors ================================================ FILE: openspec/changes/archive/2025-09-29-update-markdown-parser-crlf/tasks.md ================================================ ## 1. Guard the regression - [x] 1.1 Add a unit test that feeds a CRLF change document into `MarkdownParser.parseChange` and asserts `Why`/`What Changes` are detected. - [x] 1.2 Add a CLI spawn/e2e test that writes a CRLF change, runs `openspec validate`, and expects success. ## 2. Normalize parsing - [x] 2.1 Normalize line endings when constructing `MarkdownParser` so headers and content comparisons ignore `\r`. - [x] 2.2 Ensure all CLI entry points (validate, view, spec conversion) reuse the normalized parser path. ## 3. Document and verify - [x] 3.1 Update the `cli-validate` spec with a scenario covering CRLF line endings. - [x] 3.2 Run the parser and CLI test suites (`pnpm test`, relevant spawn tests) to confirm the fix. ================================================ FILE: openspec/changes/archive/2025-10-14-add-codex-slash-command-support/proposal.md ================================================ ## Why - Codex (the VS Code extension formerly known as Codeium Chat) exposes "slash commands" by reading Markdown prompt files from `~/.codex/prompts/`. Each file name becomes the `/command` users can run, with YAML frontmatter for metadata (`description`, `argument-hint`) and `$ARGUMENTS` to capture user input. The workflow screenshot shared by Kevin Kern ("Codex problem analyzer") shows the format OpenSpec should target so teams can invoke curated workflows straight from the chat palette. - Teams already rely on OpenSpec to manage the slash-command surface area for Claude, Cursor, OpenCode, Kilo Code, and Windsurf. Leaving Codex out forces them to manually copy/paste OpenSpec guardrails into `~/.codex/prompts/*.md`, which drifts quickly and undermines the "single source of truth" promise of the CLI. - Codex commands live outside the repository (under the user's home directory), so shipping an automated configurator that both scaffolds the prompts and keeps them refreshed via `openspec update` eliminates error-prone manual steps and keeps OpenSpec instructions synchronized across assistants. ## What Changes - Add Codex to the `openspec init` tool picker with the same "already configured" detection we use for other editors, wiring an implementation that writes managed Markdown prompts directly to Codex's global directory (`~/.codex/prompts` or `$CODEX_HOME/prompts`) with OpenSpec marker blocks. - Produce three Codex prompt files—`openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`—whose content mirrors the shared slash-command templates while using YAML frontmatter (`description` and `argument-hint` fields) and `$ARGUMENTS` to capture all arguments as a single string (matching the GitHub Copilot pattern and official Codex specification). - Document Codex's global-only discovery and that OpenSpec writes prompts directly to `~/.codex/prompts` (or `$CODEX_HOME/prompts`). - Teach `openspec update` to refresh existing Codex prompts in-place (and only when they already exist) in the global directory, updating both frontmatter and body. - Document Codex support alongside other slash-command integrations and add regression coverage that exercises init/update behaviour against a temporary global prompts directory via `CODEX_HOME`. ## Impact - Specs: `cli-init`, `cli-update` - Code: `src/core/config.ts`, `src/core/configurators/slash/*`, `src/core/templates/slash-command-templates.ts`, CLI tool summaries, docs - Tests: integration coverage for Codex prompt scaffolding and refresh logic - Docs: README and CHANGELOG entries announcing Codex slash-command support ## Current Spec Reference - `specs/cli-init/spec.md` - Requirements cover init UX, directory scaffolding, AI tool configuration, and the existing slash-command support for Claude Code, Cursor, and OpenCode. - Our `## MODIFIED` delta in `changes/.../specs/cli-init/spec.md` copies the full "Slash Command Configuration" requirement (header, description, and all scenarios) before appending the new Codex scenario so archiving will retain every prior scenario. - `specs/cli-update/spec.md` - Requirements define update preconditions, template refresh behavior, and slash-command refresh logic for Claude Code, Cursor, and OpenCode. - The corresponding delta preserves the entire "Slash Command Updates" requirement while adding the Codex refresh scenario, ensuring the archive workflow replaces the block without losing the existing scenarios or the "Missing slash command file" guardrail. ================================================ FILE: openspec/changes/archive/2025-10-14-add-codex-slash-command-support/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: AI Tool Configuration The command SHALL configure AI coding assistants with OpenSpec instructions using a marker system. #### Scenario: Prompting for AI tool selection - **WHEN** run interactively - **THEN** prompt the user with "Which AI tools do you use?" using a multi-select menu - **AND** list every available tool with a checkbox: - Claude Code (creates or refreshes CLAUDE.md and slash commands) - Cursor (creates or refreshes `.cursor/commands/*` slash commands) - OpenCode (creates or refreshes `.opencode/command/openspec-*.md` slash commands) - Windsurf (creates or refreshes `.windsurf/workflows/openspec-*.md` workflows) - Kilo Code (creates or refreshes `.kilocode/workflows/openspec-*.md` workflows) - Codex (creates or refreshes global prompts at `~/.codex/prompts/openspec-*.md`) - AGENTS.md standard (creates or refreshes AGENTS.md with OpenSpec markers) - **AND** show "(already configured)" beside tools whose managed files exist so users understand selections will refresh content - **AND** treat disabled tools as "coming soon" and keep them unselectable - **AND** allow confirming with Enter after selecting one or more tools ### Requirement: Slash Command Configuration The init command SHALL generate slash command files for supported editors using shared templates. #### Scenario: Generating slash commands for Claude Code - **WHEN** the user selects Claude Code during initialization - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cursor - **WHEN** the user selects Cursor during initialization - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for OpenCode - **WHEN** the user selects OpenCode during initialization - **THEN** create `.opencode/command/openspec-proposal.md`, `.opencode/command/openspec-apply.md`, and `.opencode/command/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Windsurf - **WHEN** the user selects Windsurf during initialization - **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Kilo Code - **WHEN** the user selects Kilo Code during initialization - **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Codex - **WHEN** the user selects Codex during initialization - **THEN** create global prompt files at `~/.codex/prompts/openspec-proposal.md`, `~/.codex/prompts/openspec-apply.md`, and `~/.codex/prompts/openspec-archive.md` (or under `$CODEX_HOME/prompts` if set) - **AND** populate each file from shared templates that map the first numbered placeholder (`$1`) to the primary user input (e.g., change identifier or question text) - **AND** wrap the generated content in OpenSpec markers so `openspec update` can refresh the prompts without touching surrounding custom notes ================================================ FILE: openspec/changes/archive/2025-10-14-add-codex-slash-command-support/specs/cli-update/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Slash Command Updates The update command SHALL refresh existing slash command files for configured tools without creating new ones. #### Scenario: Updating slash commands for Claude Code - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Cursor - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for OpenCode - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Windsurf - **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage - **AND** skip creating missing files (the update command only refreshes what already exists) #### Scenario: Updating slash commands for Kilo Code - **WHEN** `.kilocode/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage - **AND** skip creating missing files (the update command only refreshes what already exists) #### Scenario: Updating slash commands for Codex - **GIVEN** the global Codex prompt directory contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **WHEN** a user runs `openspec update` - **THEN** refresh each file using the shared slash-command templates (including placeholder guidance) - **AND** preserve any unmanaged content outside the OpenSpec marker block - **AND** skip creation when a Codex prompt file is missing #### Scenario: Missing slash command file - **WHEN** a tool lacks a slash command file - **THEN** do not create a new file during update ================================================ FILE: openspec/changes/archive/2025-10-14-add-codex-slash-command-support/tasks.md ================================================ ## 1. CLI integration - [x] 1.1 Add Codex to the init tool picker with display text that clarifies prompts live in the global `.codex/prompts/` directory and implement "already configured" detection by checking for managed Codex prompt files. - [x] 1.2 Implement a `CodexSlashCommandConfigurator` that writes `.codex/prompts/openspec-{proposal,apply,archive}.md`, ensuring the prompt directory exists and wrapping content in OpenSpec markers. // (No helper command required) - [x] 1.3 Register the configurator with the slash-command registry and include Codex in init/update wiring so both commands invoke the new configurator when appropriate. ## 2. Prompt templates - [x] 2.1 Extend the shared slash-command templates (or add a Codex-specific wrapper) to inject numbered placeholders (`$1`, `$2`, …) where Codex expects user-supplied arguments. - [x] 2.2 Verify generated Markdown stays within Codex's formatting expectations (no front matter, heading-first layout) and matches the problem-analyzer style shown in the reference screenshot. ## 3. Update support & tests - [x] 3.1 Update the `openspec update` flow to refresh existing Codex prompts without creating new ones when files are missing. - [x] 3.2 Add integration coverage that exercises init/update against a temporary global Codex prompts directory by setting `CODEX_HOME`, asserting marker preservation and idempotent updates. - [x] 3.3 Document Codex's global-only discovery and automatic installation in README and CHANGELOG. - [x] 3.3 Confirm error handling surfaces clear paths when the CLI cannot write to the Codex prompt directory (permissions, missing home directory, etc.). ## 4. Documentation - [x] 4.1 Document Codex slash-command support in the README and changelog alongside other assistant integrations. - [x] 4.2 Add a release note snippet that points Codex users to the generated `/openspec-proposal`, `/openspec-apply`, and `/openspec-archive` commands. ================================================ FILE: openspec/changes/archive/2025-10-14-add-github-copilot-prompts/proposal.md ================================================ ## Why - GitHub Copilot supports custom slash commands through markdown files in `.github/prompts/.prompt.md`. Each file includes YAML frontmatter with a `description` label and uses `$ARGUMENTS` to capture user input. This format allows teams to expose curated workflows directly in Copilot's chat interface. - Teams already rely on OpenSpec to manage slash-command configurations for Claude Code, Cursor, OpenCode, Codex, Kilo Code, and Windsurf. Excluding GitHub Copilot forces developers to manually maintain OpenSpec prompts in `.github/prompts/`, which leads to drift and undermines OpenSpec's "single source of truth" promise. - GitHub Copilot discovers prompts from the repository's `.github/prompts/` directory, making it straightforward to version control and share across the team. Adding automated generation and refresh through `openspec init` and `openspec update` eliminates manual synchronization and keeps OpenSpec instructions consistent across all AI assistants. ## What Changes - Add GitHub Copilot to the `openspec init` tool picker with "already configured" detection similar to other editors, wiring an implementation that writes managed Markdown prompt files to `.github/prompts/` with OpenSpec marker blocks. - Generate three GitHub Copilot prompt files—`openspec-proposal.prompt.md`, `openspec-apply.prompt.md`, and `openspec-archive.prompt.md`—whose content mirrors shared slash-command templates while conforming to Copilot's frontmatter and `$ARGUMENTS` placeholder convention. - Document GitHub Copilot's repository-based discovery and that OpenSpec writes prompts to `.github/prompts/` with managed blocks. - Teach `openspec update` to refresh existing GitHub Copilot prompts in-place (only when they already exist) in the repository's `.github/prompts/` directory. - Document GitHub Copilot support alongside other slash-command integrations and add test coverage that exercises init/update behavior for `.github/prompts/` files. ## Impact - Specs: `cli-init`, `cli-update` - Code: `src/core/configurators/slash/github-copilot.ts` (new), `src/core/configurators/slash/registry.ts`, `src/core/templates/slash-command-templates.ts`, CLI tool summaries, docs - Tests: integration coverage for GitHub Copilot prompt scaffolding and refresh logic - Docs: README and CHANGELOG entries announcing GitHub Copilot slash-command support ## Current Spec Reference - `specs/cli-init/spec.md` - Requirements cover init UX, directory scaffolding, AI tool configuration, and existing slash-command support for Claude Code, Cursor, OpenCode, Codex, Kilo Code, and Windsurf. - Our `## MODIFIED` delta in `changes/.../specs/cli-init/spec.md` will copy the full "Slash Command Configuration" requirement (header, description, and all scenarios) before appending the new GitHub Copilot scenario so archiving retains every prior scenario. - `specs/cli-update/spec.md` - Requirements define update preconditions, template refresh behavior, and slash-command refresh logic for existing tools. - The corresponding delta preserves the entire "Slash Command Updates" requirement while adding the GitHub Copilot refresh scenario, ensuring the archive workflow replaces the block without losing existing scenarios or the "Missing slash command file" guardrail. ================================================ FILE: openspec/changes/archive/2025-10-14-add-github-copilot-prompts/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Slash Command Configuration The init command SHALL generate slash command files for supported editors using shared templates. #### Scenario: Generating slash commands for Claude Code - **WHEN** the user selects Claude Code during initialization - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cursor - **WHEN** the user selects Cursor during initialization - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for OpenCode - **WHEN** the user selects OpenCode during initialization - **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Windsurf - **WHEN** the user selects Windsurf during initialization - **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Kilo Code - **WHEN** the user selects Kilo Code during initialization - **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Codex - **WHEN** the user selects Codex during initialization - **THEN** create global prompt files at `~/.codex/prompts/openspec-proposal.md`, `~/.codex/prompts/openspec-apply.md`, and `~/.codex/prompts/openspec-archive.md` (or under `$CODEX_HOME/prompts` if set) - **AND** populate each file from shared templates that map the first numbered placeholder (`$1`) to the primary user input (e.g., change identifier or question text) - **AND** wrap the generated content in OpenSpec markers so `openspec update` can refresh the prompts without touching surrounding custom notes #### Scenario: Generating slash commands for GitHub Copilot - **WHEN** the user selects GitHub Copilot during initialization - **THEN** create `.github/prompts/openspec-proposal.prompt.md`, `.github/prompts/openspec-apply.prompt.md`, and `.github/prompts/openspec-archive.prompt.md` - **AND** populate each file with YAML frontmatter containing a `description` field that summarizes the workflow stage - **AND** include `$ARGUMENTS` placeholder to capture user input - **AND** wrap the shared template body with OpenSpec markers so `openspec update` can refresh the content - **AND** each template includes instructions for the relevant OpenSpec workflow stage ================================================ FILE: openspec/changes/archive/2025-10-14-add-github-copilot-prompts/specs/cli-update/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Slash Command Updates The update command SHALL refresh existing slash command files for configured tools without creating new ones. #### Scenario: Updating slash commands for Claude Code - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Cursor - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for OpenCode - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Windsurf - **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage - **AND** skip creating missing files (the update command only refreshes what already exists) #### Scenario: Updating slash commands for Kilo Code - **WHEN** `.kilocode/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage - **AND** skip creating missing files (the update command only refreshes what already exists) #### Scenario: Updating slash commands for Codex - **GIVEN** the global Codex prompt directory contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **WHEN** a user runs `openspec update` - **THEN** refresh each file using the shared slash-command templates (including placeholder guidance) - **AND** preserve any unmanaged content outside the OpenSpec marker block - **AND** skip creation when a Codex prompt file is missing #### Scenario: Updating slash commands for GitHub Copilot - **WHEN** `.github/prompts/` contains `openspec-proposal.prompt.md`, `openspec-apply.prompt.md`, and `openspec-archive.prompt.md` - **THEN** refresh each file using shared templates while preserving the YAML frontmatter - **AND** update only the OpenSpec-managed block between markers - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Missing slash command file - **WHEN** a tool lacks a slash command file - **THEN** do not create a new file during update ================================================ FILE: openspec/changes/archive/2025-10-14-add-github-copilot-prompts/tasks.md ================================================ ## Implementation Tasks - [x] Create `src/core/configurators/slash/github-copilot.ts` implementing `SlashCommandConfigurator` base class - Implement `getRelativePath()` to return `.github/prompts/openspec-{proposal,apply,archive}.prompt.md` - Implement `getFrontmatter()` to generate YAML frontmatter with `description` field and include `$ARGUMENTS` placeholder - Implement `generateAll()` to create `.github/prompts/` directory and write three prompt files with frontmatter, markers, and shared template bodies - Implement `updateExisting()` to refresh only the managed block between markers while preserving frontmatter - Set `toolId = "github-copilot"` and `isAvailable = true` - [x] Register GitHub Copilot configurator in `src/core/configurators/slash/registry.ts` - Import `GitHubCopilotSlashCommandConfigurator` - Add to `SLASH_COMMAND_CONFIGURATORS` array - Update tool picker display name to "GitHub Copilot" - [x] Update `src/core/init.ts` to include GitHub Copilot in the AI tool selection prompt - Add GitHub Copilot to the available tools list with detection for existing `.github/prompts/openspec-*.prompt.md` files - Display "(already configured)" when prompt files exist - [x] Update `src/core/update.ts` to refresh GitHub Copilot prompts when they exist - Call `updateExisting()` for GitHub Copilot configurator when `.github/prompts/` contains OpenSpec prompt files - [x] Add integration tests for GitHub Copilot slash command generation - Test `generateAll()` creates three prompt files with correct structure (frontmatter + markers + body) - Test `updateExisting()` preserves frontmatter and only updates managed blocks - Test that missing prompt files are not created during update - [x] Update documentation - Add GitHub Copilot to README slash-command support table - Document `.github/prompts/` as the discovery location - Add CHANGELOG entry for GitHub Copilot support ================================================ FILE: openspec/changes/archive/2025-10-14-add-kilocode-workflows/proposal.md ================================================ ## Why - Kilo Code executes \"slash commands\" by loading markdown workflows from `.kilocode/workflows/` (or the global `~/.kilocode/workflows/`) and running them when a user types `/workflow-name.md`, making project-local workflow files the analogue to the slash-command files we already ship for other tools.\\ ([Workflows | Kilo Code Docs](https://kilocode.ai/docs/features/slash-commands/workflows)) - Those workflows are plain markdown with step-by-step instructions that can call built-in tools and MCP integrations, so reusing OpenSpec's shared proposal/apply/archive bodies keeps behaviour aligned across assistants without inventing new content. - OpenSpec already detects configured tools and refreshes marker-wrapped files during `init`/`update`; extending the same mechanism to `.kilocode/workflows/openspec-*.md` ensures Kilo Code stays in sync with one source of truth. ## What Changes - Add Kilo Code to the `openspec init` tool picker with \"already configured\" detection, including wiring for extend mode so teams can refresh Kilo Code assets. - Implement a `KiloCodeSlashCommandConfigurator` that creates `.kilocode/workflows/openspec-{proposal,apply,archive}.md`, ensuring the workflow directory exists and wrapping shared content in OpenSpec markers (no front matter required). - Teach `openspec update` to refresh existing Kilo Code workflows (and only those that already exist) using the shared slash-command templates. - Update documentation, release notes, and integration tests so the new workflow support is covered alongside Claude, Cursor, OpenCode, and Windsurf. ## Impact - Specs: `cli-init`, `cli-update` - Code: `src/core/config.ts`, `src/core/configurators/(registry|slash/*)`, `src/core/templates/slash-command-templates.ts`, CLI wiring for tool summaries - Tests: init/update workflow coverage, regression for marker preservation in `.kilocode/workflows/` - Docs: README / CHANGELOG updates advertising Kilo Code workflow support ================================================ FILE: openspec/changes/archive/2025-10-14-add-kilocode-workflows/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: AI Tool Configuration The command SHALL configure AI coding assistants with OpenSpec instructions using a marker system. #### Scenario: Prompting for AI tool selection - **WHEN** run interactively - **THEN** prompt the user with "Which AI tools do you use?" using a multi-select menu - **AND** list every available tool with a checkbox: - Claude Code (creates or refreshes CLAUDE.md and slash commands) - Cursor (creates or refreshes `.cursor/commands/*` slash commands) - OpenCode (creates or refreshes `.opencode/command/openspec-*.md` slash commands) - Windsurf (creates or refreshes `.windsurf/workflows/openspec-*.md` workflows) - Kilo Code (creates or refreshes `.kilocode/workflows/openspec-*.md` workflows) - AGENTS.md standard (creates or refreshes AGENTS.md with OpenSpec markers) - **AND** show "(already configured)" beside tools whose managed files exist so users understand selections will refresh content - **AND** treat disabled tools as "coming soon" and keep them unselectable - **AND** allow confirming with Enter after selecting one or more tools ### Requirement: Slash Command Configuration The init command SHALL generate slash command files for supported editors using shared templates. #### Scenario: Generating slash commands for Claude Code - **WHEN** the user selects Claude Code during initialization - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cursor - **WHEN** the user selects Cursor during initialization - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for OpenCode - **WHEN** the user selects OpenCode during initialization - **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Kilo Code - **WHEN** the user selects Kilo Code during initialization - **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage ================================================ FILE: openspec/changes/archive/2025-10-14-add-kilocode-workflows/specs/cli-update/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Slash Command Updates The update command SHALL refresh existing slash command files for configured tools without creating new ones. #### Scenario: Updating slash commands for Claude Code - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Cursor - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for OpenCode - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Kilo Code - **WHEN** `.kilocode/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Missing slash command file - **WHEN** a tool lacks a slash command file - **THEN** do not create a new file during update ================================================ FILE: openspec/changes/archive/2025-10-14-add-kilocode-workflows/tasks.md ================================================ ## 1. CLI wiring - [x] 1.1 Add Kilo Code to the selectable AI tools in `openspec init`, including "already configured" detection and success summaries. - [x] 1.2 Register a `KiloCodeSlashCommandConfigurator` alongside other slash-command tools. ## 2. Workflow generation - [x] 2.1 Implement the configurator so it creates `.kilocode/workflows/` (if needed) and writes `openspec-{proposal,apply,archive}.md` with OpenSpec markers. - [x] 2.2 Reuse the shared slash-command bodies without front matter; verify resulting files stay Markdown-only with no extra metadata. ## 3. Update support - [x] 3.1 Ensure `openspec update` refreshes existing Kilo Code workflows while skipping ones that are absent. - [x] 3.2 Add regression coverage confirming marker content is replaced (not duplicated) during updates. ## 4. Documentation - [x] 4.1 Update README / docs to note Kilo Code workflow support and path (`.kilocode/workflows/`). - [x] 4.2 Mention the integration in CHANGELOG or release notes if applicable. ================================================ FILE: openspec/changes/archive/2025-10-14-add-non-interactive-init-options/proposal.md ================================================ ## Why The current `openspec init` command requires interactive prompts, preventing automation in CI/CD pipelines and scripted setups. Adding non-interactive options will enable programmatic initialization for automated workflows while maintaining the existing interactive experience as the default. ## What Changes - Replace the multiple flag design with a single `--tools` option that accepts `all`, `none`, or a comma-separated list of tool IDs - Update InitCommand to bypass interactive prompts when `--tools` is supplied and apply single-flag validation rules - Document the non-interactive behavior via the CLI init spec delta (scenarios for `all`, `none`, list parsing, and invalid entries) - Generate CLI help text dynamically from `AI_TOOLS` so supported tools stay in sync ## Impact - Affected specs: `specs/cli-init/spec.md` - Affected code: `src/cli/index.ts`, `src/core/init.ts` ================================================ FILE: openspec/changes/archive/2025-10-14-add-non-interactive-init-options/specs/cli-init/spec.md ================================================ # Delta for CLI Init Specification ## ADDED Requirements ### Requirement: Non-Interactive Mode The command SHALL support non-interactive operation through command-line options for automation and CI/CD use cases. #### Scenario: Select all tools non-interactively - **WHEN** run with `--tools all` - **THEN** automatically select every available AI tool without prompting - **AND** proceed with initialization using the selected tools #### Scenario: Select specific tools non-interactively - **WHEN** run with `--tools claude,cursor` - **THEN** parse the comma-separated tool IDs and validate against available tools - **AND** proceed with initialization using only the specified valid tools #### Scenario: Skip tool configuration non-interactively - **WHEN** run with `--tools none` - **THEN** skip AI tool configuration entirely - **AND** only create the OpenSpec directory structure and template files #### Scenario: Invalid tool specification - **WHEN** run with `--tools` containing any IDs not present in the AI tool registry - **THEN** exit with code 1 and display available values (`all`, `none`, or the supported tool IDs) #### Scenario: Help text lists available tool IDs - **WHEN** displaying CLI help for `openspec init` - **THEN** show the `--tools` option description with the valid values derived from the AI tool registry ## MODIFIED Requirements ### Requirement: Interactive Mode The command SHALL provide an interactive menu for AI tool selection with clear navigation instructions. #### Scenario: Displaying interactive menu - **WHEN** run in fresh or extend mode without non-interactive options - **THEN** present a looping select menu that lets users toggle tools with Enter and finish via a "Done" option - **AND** label already configured tools with "(already configured)" while keeping disabled options marked "coming soon" - **AND** change the prompt copy in extend mode to "Which AI tools would you like to add or refresh?" - **AND** display inline instructions clarifying that Enter toggles a tool and selecting "Done" confirms the list ================================================ FILE: openspec/changes/archive/2025-10-14-add-non-interactive-init-options/tasks.md ================================================ ## 1. CLI Option Registration - [x] 1.1 Replace the multiple flag design with a single `--tools ` option supporting `all|none|a,b,c` and keep strict argument validation. - [x] 1.2 Populate the `--tools` help text dynamically from the `AI_TOOLS` registry. ## 2. InitCommand Modifications - [x] 2.1 Accept the single tools option in the InitCommand constructor and plumb it through existing flows. - [x] 2.2 Update tool selection logic to shortcut prompts for `all`, `none`, and explicit lists. - [x] 2.3 Fail fast with exit code 1 and a helpful message when the parsed list contains unsupported tool IDs. ## 3. Specification Updates - [x] 3.1 Capture the non-interactive scenarios (`all`, `none`, list, invalid) in the change delta without modifying `specs/cli-init/spec.md` directly. - [x] 3.2 Document that CLI help reflects the available tool IDs managed by `AI_TOOLS`. ## 4. Testing - [x] 4.1 Add unit coverage for parsing `--tools` values, including invalid entries. - [x] 4.2 Add integration coverage ensuring non-interactive runs generate the expected files and exit codes. - [x] 4.3 Verify the interactive flow remains unchanged when `--tools` is omitted. ================================================ FILE: openspec/changes/archive/2025-10-14-add-windsurf-workflows/proposal.md ================================================ ## Why - Windsurf exposes "Workflows" as the vehicle for slash-like automation: saved Markdown files under `.windsurf/workflows/` that Cascade discovers across the workspace (including subdirectories and up to the git root), then executes when a user types `/workflow-name`. These files can be team-authored, must stay under 12k characters, and can call other workflows, making them the natural place to publish OpenSpec guidance for Windsurf users.\ ([Windsurf Workflows documentation](https://docs.windsurf.com/windsurf/cascade/workflows)) - The Wave 12 changelog reiterates that workflows are invoked via slash commands and that Windsurf stores them in `.windsurf/workflows`, so the OpenSpec CLI just needs to generate Markdown there to participate in Windsurf's command palette.\ ("Custom Workflows" section, [Windsurf changelog](https://windsurf.com/changelog)) - OpenSpec already ships shared command bodies for proposal/apply/archive and uses markers so commands stay up to date. Extending the same templates to Windsurf keeps behaviour consistent with Claude, Cursor, and OpenCode without inventing new content flows. ## What Changes - Add Windsurf to the CLI tool picker (`openspec init`) and the slash-command registry so selecting it scaffolds `.windsurf/workflows/openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` with marker-managed bodies. - Shape each Windsurf workflow with a short heading/description plus the existing OpenSpec guardrails/steps wrapped in markers, ensuring the total payload remains well below the 12,000 character limit. - Ensure `openspec update` refreshes existing Windsurf workflows (and only those that already exist) in-place, mirroring current behaviour for other editors. - Extend unit tests for init/update to cover Windsurf generation and updates, and update the README/tooling docs to advertise Windsurf support. ## Impact - Specs: `cli-init`, `cli-update` - Code: `src/core/configurators/slash/*`, `src/core/templates/slash-command-templates.ts`, CLI prompts, README - Tests: init/update integration coverage for Windsurf workflows ================================================ FILE: openspec/changes/archive/2025-10-14-add-windsurf-workflows/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: AI Tool Configuration The command SHALL configure AI coding assistants with OpenSpec instructions using a marker system. #### Scenario: Prompting for AI tool selection - **WHEN** run interactively - **THEN** prompt the user with "Which AI tools do you use?" using a multi-select menu - **AND** list every available tool with a checkbox: - Claude Code (creates or refreshes CLAUDE.md and slash commands) - Cursor (creates or refreshes `.cursor/commands/*` slash commands) - OpenCode (creates or refreshes `.opencode/command/openspec-*.md` slash commands) - Windsurf (creates or refreshes `.windsurf/workflows/openspec-*.md` workflows) - AGENTS.md standard (creates or refreshes AGENTS.md with OpenSpec markers) - **AND** show "(already configured)" beside tools whose managed files exist so users understand selections will refresh content - **AND** treat disabled tools as "coming soon" and keep them unselectable - **AND** allow confirming with Enter after selecting one or more tools ### Requirement: Slash Command Configuration The init command SHALL generate slash command files for supported editors using shared templates. #### Scenario: Generating slash commands for Claude Code - **WHEN** the user selects Claude Code during initialization - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cursor - **WHEN** the user selects Cursor during initialization - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for OpenCode - **WHEN** the user selects OpenCode during initialization - **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Windsurf - **WHEN** the user selects Windsurf during initialization - **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage ================================================ FILE: openspec/changes/archive/2025-10-14-add-windsurf-workflows/specs/cli-update/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Slash Command Updates The update command SHALL refresh existing slash command files for configured tools without creating new ones. #### Scenario: Updating slash commands for Claude Code - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Cursor - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for OpenCode - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Windsurf - **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Missing slash command file - **WHEN** a tool lacks a slash command file - **THEN** do not create a new file during update ================================================ FILE: openspec/changes/archive/2025-10-14-add-windsurf-workflows/tasks.md ================================================ ## 1. CLI wiring - [x] 1.1 Add Windsurf to the selectable AI tools in `openspec init`, including "already configured" detection. - [x] 1.2 Register a `WindsurfSlashCommandConfigurator` that writes workflows to `.windsurf/workflows/` and ensures the directory exists. - [x] 1.3 Ensure `openspec update` pulls the Windsurf configurator when winds is selected and skips creation when files are absent. ## 2. Workflow templates - [x] 2.1 Reuse the shared proposal/apply/archive bodies, adding Windsurf-specific headings/description before the OpenSpec markers. - [x] 2.2 Confirm generated Markdown (per file) stays comfortably under the 12k character ceiling noted in the Windsurf docs. ## 3. Tests & safeguards - [x] 3.1 Extend init tests to assert creation of `.windsurf/workflows/openspec-*.md` when Windsurf is chosen. - [x] 3.2 Extend update tests to assert existing Windsurf workflows are refreshed and non-existent files are ignored. - [x] 3.3 Add regression coverage for marker preservation inside Windsurf workflow files. ## 4. Documentation - [x] 4.1 Update README (and any user-facing docs) to list Windsurf under native slash/workflow integrations. - [x] 4.2 Call out Windsurf workflow support in release notes or CHANGELOG if applicable. ================================================ FILE: openspec/changes/archive/2025-10-14-enhance-validation-error-messages/proposal.md ================================================ ## Why Validation errors like "no deltas found" or "missing requirement text" do not tell agents how to recover, leading to repeated failures. Making error output specific about headers, required text, and next actions will help assistants fix issues in a single pass. ## What Changes - Extend `openspec validate` error reporting so each failure names the exact header, file, and expected structure, including concrete examples of compliant Markdown. - Tailor messages for the most common mistakes (missing delta sections, absent descriptive requirement text, missing scenarios) with actionable fixes and suggested debug commands. - Update docs/help output so the improved messaging is discoverable (e.g., `--help`, troubleshooting section). - Add regression coverage to lock in the richer messaging for the top validation paths. ## Impact - Affected specs: `specs/cli-validate` - Affected code: `src/commands/validate.ts`, `src/core/validation`, `docs/` ================================================ FILE: openspec/changes/archive/2025-10-14-enhance-validation-error-messages/specs/cli-validate/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Validation SHALL provide actionable remediation steps Validation output SHALL include specific guidance to fix each error, including expected structure, example headers, and suggested commands to verify fixes. #### Scenario: No deltas found in change - **WHEN** validating a change with zero parsed deltas - **THEN** show error "No deltas found" with guidance: - Explain that change specs must include `## ADDED Requirements`, `## MODIFIED Requirements`, `## REMOVED Requirements`, or `## RENAMED Requirements` - Remind authors that files must live under `openspec/changes/{id}/specs//spec.md` - Include an explicit note: "Spec delta files cannot start with titles before the operation headers" - Suggest running `openspec change show {id} --json --deltas-only` for debugging #### Scenario: Missing required sections - **WHEN** a required section is missing - **THEN** include expected header names and a minimal skeleton: - For Spec: `## Purpose`, `## Requirements` - For Change: `## Why`, `## What Changes` - Provide an example snippet of the missing section with placeholder prose ready to copy - Mention the quick-reference section in `openspec/AGENTS.md` as the authoritative template #### Scenario: Missing requirement descriptive text - **WHEN** a requirement header lacks descriptive text before scenarios - **THEN** emit an error explaining that `### Requirement:` lines must be followed by narrative text before any `#### Scenario:` headers - Show compliant example: "### Requirement: Foo" followed by "The system SHALL ..." - Suggest adding 1-2 sentences describing the normative behavior prior to listing scenarios - Reference the pre-validation checklist in `openspec/AGENTS.md` ### Requirement: Validator SHALL detect likely misformatted scenarios and warn with a fix The validator SHALL recognize bulleted lines that look like scenarios (e.g., lines beginning with WHEN/THEN/AND) and emit a targeted warning with a conversion example to `#### Scenario:`. #### Scenario: Bulleted WHEN/THEN under a Requirement - **WHEN** bullets that start with WHEN/THEN/AND are found under a requirement without any `#### Scenario:` headers - **THEN** emit warning: "Scenarios must use '#### Scenario:' headers", and show a conversion template: ``` #### Scenario: Short name - **WHEN** ... - **THEN** ... - **AND** ... ``` ================================================ FILE: openspec/changes/archive/2025-10-14-enhance-validation-error-messages/tasks.md ================================================ ## 1. Messaging enhancements - [x] 1.1 Inventory current validation failures and map each to the desired message improvements. - [x] 1.2 Implement structured error builders that include file paths, normalized header names, and example fixes. - [x] 1.3 Ensure `openspec validate --help` and troubleshooting docs mention the richer messages and debug tips. ## 2. Tests - [x] 2.1 Add unit tests for representative errors (no deltas, missing requirement body, missing scenarios) asserting the new wording. - [x] 2.2 Add integration coverage verifying the Next steps footer reflects contextual guidance. ## 3. Documentation - [x] 3.1 Update troubleshooting sections and CLI docs with sample output from the enhanced errors. - [x] 3.2 Note the change in CHANGELOG or release notes if applicable. ================================================ FILE: openspec/changes/archive/2025-10-14-improve-agent-instruction-usability/proposal.md ================================================ ## Why Agents fumble proposal formatting because the essential Markdown templates and formatting rules are buried mid-document. Reorganizing `openspec/AGENTS.md` with a prominent quick-reference and embedded examples will help assistants follow the process without guesswork. ## What Changes - Restructure `openspec/AGENTS.md` so file formats and scaffold templates appear in a top-level quick-reference section before workflow prose. - Embed copy/paste templates for `proposal.md`, `tasks.md`, `design.md`, and spec deltas alongside inline examples within the workflow steps. - Add a pre-validation checklist that highlights the most common formatting pitfalls before running `openspec validate`. - Split content into beginner vs. advanced sections to progressively disclose complexity while keeping advanced guidance accessible. ## Impact - Affected specs: `specs/docs-agent-instructions` - Affected code: `openspec/AGENTS.md`, `docs/` ================================================ FILE: openspec/changes/archive/2025-10-14-improve-agent-instruction-usability/specs/docs-agent-instructions/spec.md ================================================ ## ADDED Requirements ### Requirement: Quick Reference Placement The AI instructions SHALL begin with a quick-reference section that surfaces required file structures, templates, and formatting rules before any narrative guidance. #### Scenario: Loading templates at the top - **WHEN** `openspec/AGENTS.md` is regenerated or updated - **THEN** the first substantive section after the title SHALL provide copy-ready headings for `proposal.md`, `tasks.md`, spec deltas, and scenario formatting - **AND** link each template to the corresponding workflow step for deeper reading ### Requirement: Embedded Templates and Examples `openspec/AGENTS.md` SHALL include complete copy/paste templates and inline examples exactly where agents make corresponding edits. #### Scenario: Providing file templates - **WHEN** authors reach the workflow guidance for drafting proposals and deltas - **THEN** provide fenced Markdown templates that match the required structure (`## Why`, `## ADDED Requirements`, `#### Scenario:` etc.) - **AND** accompany each template with a brief example showing correct header usage and scenario bullets ### Requirement: Pre-validation Checklist `openspec/AGENTS.md` SHALL offer a concise pre-validation checklist that highlights common formatting mistakes before running `openspec validate`. #### Scenario: Highlighting common validation failures - **WHEN** a reader reaches the validation guidance - **THEN** present a checklist reminding them to verify requirement headers, scenario formatting, and delta sections - **AND** include reminders about at least `#### Scenario:` usage and descriptive requirement text before scenarios ### Requirement: Progressive Disclosure of Workflow Guidance The documentation SHALL separate beginner essentials from advanced topics so newcomers can focus on core steps without losing access to advanced workflows. #### Scenario: Organizing beginner and advanced sections - **WHEN** reorganizing `openspec/AGENTS.md` - **THEN** keep an introductory section limited to the minimum steps (scaffold, draft, validate, request review) - **AND** move advanced topics (multi-capability changes, archiving details, tooling deep dives) into clearly labeled later sections - **AND** provide anchor links from the quick-reference to those advanced sections ================================================ FILE: openspec/changes/archive/2025-10-14-improve-agent-instruction-usability/tasks.md ================================================ ## 1. Instruction redesign - [x] 1.1 Draft a quick-reference section that surfaces file templates and formatting rules at the top of `openspec/AGENTS.md`. - [x] 1.2 Reorganize the workflow narrative with inline examples and progressive disclosure for advanced topics. ## 2. Templates and checklists - [x] 2.1 Add copy/paste templates for proposal, tasks, design, and spec delta files. - [x] 2.2 Insert a pre-validation checklist capturing common lint failures before running `openspec validate`. ## 3. Documentation updates - [x] 3.1 Update supporting docs or README pointers so contributors find the redesigned instructions. - [x] 3.2 Confirm examples and references stay in sync with the new scaffold command guidance. ================================================ FILE: openspec/changes/archive/2025-10-14-slim-root-agents-file/proposal.md ================================================ ## Why The project root currently receives a full copy of the OpenSpec agent instructions, duplicating the content that also lives in `openspec/AGENTS.md`. When teams edit one copy but not the other, the files drift and onboarding assistants see conflicting guidance. ## What Changes - Keep generating the complete template in `openspec/AGENTS.md` during `openspec init` and follow-up updates. - Replace the root-level file (`AGENTS.md` or `CLAUDE.md`, depending on tool selection) with a short hand-off that explains the project uses OpenSpec and points directly to `openspec/AGENTS.md`. - Add a dedicated stub template so both the init and update flows reuse the same minimal copy instructions. - Update CLI tests and documentation to reflect the new root-level messaging and ensure the OpenSpec marker block still protects future updates. ## Impact - Affected specs: `cli-init`, `cli-update` - Affected code: `src/core/init.ts`, `src/core/update.ts`, `src/core/templates/agents-template.ts` - Update assets/readmes that mention the root `AGENTS.md` contents to reference the new stub message. ================================================ FILE: openspec/changes/archive/2025-10-14-slim-root-agents-file/tasks.md ================================================ ## 1. Templates - [x] 1.1 Add a shared stub template that renders the root agent instructions hand-off message. - [x] 1.2 Ensure the stub covers both `AGENTS.md` and `CLAUDE.md` variants. ## 2. Init Flow - [x] 2.1 Update `createInitArtifacts` to write the stub to the project root instead of the full instructions. - [x] 2.2 Preserve the managed block markers so future updates can overwrite the stub safely. ## 3. Update Flow - [x] 3.1 Make the update command refresh the root stub rather than the full instructions. - [x] 3.2 Confirm the update log output still reflects the files that changed. ## 4. Tests & Docs - [x] 4.1 Adjust CLI/init tests to match the new root content. - [x] 4.2 Document the stub message in `openspec/specs/cli-init` and `openspec/specs/cli-update` (and any relevant README snippets). ================================================ FILE: openspec/changes/archive/2025-10-14-update-cli-init-enter-selection/proposal.md ================================================ ## Why - Users frequently scroll to a tool and press Enter without toggling it, resulting in no configuration changes. - The current workflow deviates from common CLI expectations where Enter confirms the highlighted item. - Aligning behavior with user expectations reduces friction during onboarding. ## What Changes - Update the init wizard so pressing Enter on a highlighted tool selects it before moving to the review step. - Adjust interactive instructions to clarify Enter selects the current tool and Space still toggles selections. - Refresh specs to capture the clarified behavior for the interactive menu. ## Impact - Users who press Enter without toggling now configure the highlighted tool instead of exiting with no selections. - Spacebar multi-select support remains unchanged for power users. - Documentation better reflects how the wizard behaves. ================================================ FILE: openspec/changes/archive/2025-10-14-update-cli-init-enter-selection/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Interactive Mode The command SHALL provide an interactive menu for AI tool selection with clear navigation instructions. #### Scenario: Displaying interactive menu - **WHEN** run in fresh or extend mode - **THEN** present a looping select menu that lets users toggle tools with Space and review selections with Enter - **AND** when Enter is pressed on a highlighted selectable tool that is not already selected, automatically add it to the selection before moving to review so the highlighted tool is configured - **AND** label already configured tools with "(already configured)" while keeping disabled options marked "coming soon" - **AND** change the prompt copy in extend mode to "Which AI tools would you like to add or refresh?" - **AND** display inline instructions clarifying that Space toggles tools and Enter selects the highlighted tool before reviewing selections ================================================ FILE: openspec/changes/archive/2025-10-14-update-cli-init-enter-selection/tasks.md ================================================ ## 1. Implementation - [x] Update the tool selection wizard to auto-select the highlighted tool when Enter is pressed without prior toggles. - [x] Refresh inline instructions copy so Enter behavior is clear. - [x] Adjust or add tests if needed to cover the new selection flow. ## 2. Validation - [x] Run `pnpm run build`. - [x] Run `pnpm test` (or targeted suite) if applicable. ================================================ FILE: openspec/changes/archive/2025-10-14-update-cli-init-root-agents/proposal.md ================================================ ## Why OpenSpec currently creates the root-level `AGENTS.md` stub only when teams explicitly select the "AGENTS.md standard" tool during `openspec init`. Projects that skip that checkbox never get a managed stub, so non-native assistants (Copilot, Codeium, etc.) have no entry point and later `openspec update` runs silently create the file without any context. We need to bake the stub into initialization, clarify the tool selection experience, and keep the update workflow aligned so every teammate lands on the right instructions from day one. ## What Changes - Update `openspec init` so the root `AGENTS.md` stub is always generated (first run and extend mode) and refreshed from a shared utility instead of being tied to a tool selection. - Redesign the AI tool selection wizard to split options into "Natively supported" (Claude, Cursor, OpenCode, …) and an informational "Other tools" section that explains the always-on `AGENTS.md` hand-off. - Adjust CLI specs, prompts, and success messaging to reflect the new categories while keeping extend-mode behaviour consistent. - Update automated tests and fixtures to cover the unconditional stub creation and the reworked prompt flow. - Refresh documentation and onboarding snippets so they no longer describe the stub as opt-in and instead call out the new grouping. - Ensure `openspec update` continues to reconcile both `openspec/AGENTS.md` and the root stub, documenting the expected behaviour so mismatched setups self-heal. ## Impact - Affected specs: `cli-init`, `cli-update` - Affected code: `src/core/init.ts`, `src/core/config.ts`, `src/core/configurators/agents.ts`, `src/core/templates/agents-root-stub.ts`, `src/core/update.ts`, related tests under `test/core/` - Docs & assets: README, CHANGELOG, any setup guides that reference choosing the "AGENTS.md standard" option ================================================ FILE: openspec/changes/archive/2025-10-14-update-cli-init-root-agents/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: AI Tool Configuration The command SHALL configure AI coding assistants with OpenSpec instructions using a grouped selection experience so teams can enable native integrations while always provisioning guidance for other assistants. #### Scenario: Prompting for AI tool selection - **WHEN** run interactively - **THEN** present a multi-select wizard that separates options into two headings: - **Natively supported providers** shows each available first-party integration (Claude Code, Cursor, OpenCode, …) with checkboxes - **Other tools** explains that the root-level `AGENTS.md` stub is always generated for AGENTS-compatible assistants and cannot be deselected - **AND** mark already configured native tools with "(already configured)" to signal that choosing them will refresh managed content - **AND** keep disabled or unavailable providers labelled as "coming soon" so users know they cannot opt in yet - **AND** allow confirming the selection even when no native provider is chosen because the root stub remains enabled by default - **AND** change the base prompt copy in extend mode to "Which natively supported AI tools would you like to add or refresh?" ### Requirement: Exit Code Adjustments `openspec init` SHALL treat extend mode without new native tool selections as a successful refresh. #### Scenario: Allowing empty extend runs - **WHEN** OpenSpec is already initialized and the user selects no additional natively supported tools - **THEN** complete successfully while refreshing the root `AGENTS.md` stub - **AND** exit with code 0 ## ADDED Requirements ### Requirement: Root instruction stub `openspec init` SHALL always scaffold the root-level `AGENTS.md` hand-off so every teammate finds the primary OpenSpec instructions. #### Scenario: Creating root `AGENTS.md` - **GIVEN** the project may or may not already contain an `AGENTS.md` file - **WHEN** initialization completes in fresh or extend mode - **THEN** create or refresh `AGENTS.md` at the repository root using the managed marker block from `TemplateManager.getAgentsStandardTemplate()` - **AND** preserve any existing content outside the managed markers while replacing the stub text inside them - **AND** create the stub regardless of which native AI tools are selected ================================================ FILE: openspec/changes/archive/2025-10-14-update-cli-init-root-agents/specs/cli-update/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Tool-Agnostic Updates The update command SHALL refresh OpenSpec-managed files in a predictable manner while respecting each team's chosen tooling. #### Scenario: Updating files - **WHEN** updating files - **THEN** completely replace `openspec/AGENTS.md` with the latest template - **AND** create or refresh the root-level `AGENTS.md` stub using the managed marker block, even if the file was previously absent - **AND** update only the OpenSpec-managed sections inside existing AI tool files, leaving user-authored content untouched - **AND** avoid creating new native-tool configuration files (slash commands, CLAUDE.md, etc.) unless they already exist ================================================ FILE: openspec/changes/archive/2025-10-14-update-cli-init-root-agents/tasks.md ================================================ ## 1. Implementation - [x] 1.1 Refactor `openspec init` to always generate the root `AGENTS.md` stub (initial run and extend mode) via shared helper logic. - [x] 1.2 Rework the AI tool selection wizard to surface "Natively supported" vs "Other tools" groupings and make the stub non-optional. - [x] 1.3 Update CLI messaging, templates, and configurators so the new flow stays in sync across init and update commands. - [x] 1.4 Refresh unit/integration tests to cover the unconditional stub and the regrouped prompt layout. - [x] 1.5 Update documentation, README snippets, and CHANGELOG entries that mention the opt-in `AGENTS.md` experience. ## 2. Validation - [x] 2.1 Run `pnpm test` targeting CLI init/update suites. - [x] 2.2 Execute `openspec validate update-cli-init-root-agents --strict`. - [x] 2.3 Perform a manual smoke test: run `openspec init` in a temp directory, confirm stub + grouped prompts, rerun in extend mode. ================================================ FILE: openspec/changes/archive/2025-10-14-update-release-automation/proposal.md ================================================ ## Why Today’s process requires maintainers to merge the Changesets PR, cut a tag, and draft the GitHub release by hand. npm publish then runs from our existing workflow after the GitHub release is published. The human-in-the-loop steps (versioning, tagging, release notes) slow us down and risk drift between npm, tags, and changelog. ## What Changes - Use the single `changesets/action` on pushes to `main` to either open/update the version PR or, when the release PR is merged, run our publish command automatically using repository secrets. - Add a `release` script that builds and runs `changeset publish` so the action handles version bumps, changelog commits, npm publish, and GitHub releases end-to-end. - Enable `createGithubReleases: true` so GitHub releases are created from the changeset data right after publishing. - Document the automated flow, required secrets, guardrails, and recovery steps (rollback, hotfixes). ## Two-Phase Rollout (Two PRs) 1) Phase 1 — Dry run (no publish) - Update the existing `release-prepare.yml` to wire up `changesets/action` with `createGithubReleases: true` and a no-op `publish` command (e.g., `echo 'dry run'`). - Keep `.github/workflows/release-publish.yml` intact. This avoids any publish path changes while we verify that the version PR behavior and permissions are correct. - Add a repository guard (`if: github.repository == 'Fission-AI/OpenSpec'`) and a concurrency group for safety. 2) Phase 2 — Enable publish and consolidate - Add `"release": "pnpm run build && pnpm exec changeset publish"` to `package.json`. - Change `release-prepare.yml` to use `with: publish: pnpm run release` and `env: NPM_TOKEN: \\${{ secrets.NPM_TOKEN }}` plus the default `GITHUB_TOKEN`. - Remove `.github/workflows/release-publish.yml` to avoid double-publish. Publishing now happens when the version PR is merged. ## Guardrails - Concurrency: `concurrency: { group: release-\\${{ github.ref }}, cancel-in-progress: false }` on the workflow to serialize releases. - Repository/branch guard: run publish logic only on upstream `main` (`if: github.repository == 'Fission-AI/OpenSpec' && github.ref == 'refs/heads/main'`). - Permissions: ensure `contents: write` and `pull-requests: write` for opening/updating the version PR; `packages: read` optional. ## Rollback and Hotfixes - Rollback: revert the release PR merge (which reverts version bumps/changelog); if a tag or GitHub release was created, delete the tag and release; deprecate the npm version if necessary (`npm deprecate @fission-ai/openspec@x.y.z 'reason'`). - Hotfix (urgent, no pending changesets): create a changeset for the fix and merge the release PR; in emergencies, run a manual bump/publish but reconcile with Changesets by adding a follow-up changeset to align versions. ## Required Secrets - `NPM_TOKEN` with publish rights for the `@fission-ai` scope. - Default `GITHUB_TOKEN` (provided by GitHub) for opening/updating the version PR and creating GitHub releases. ## How the Maintainer Flow Changes | Step | Current process | Future process | | --- | --- | --- | | Prepare release | Merge changeset PR, then manually draft release notes and tags | Merge release PR; action updates versions and handles changelog automatically | | Publish npm package | Happens automatically after GitHub release | Happens automatically via `changeset publish` invoked by the action | | GitHub release | Draft manually and sync with changelog | Action creates GitHub releases from changeset data | | Docs/process | Follow manual tagging/release steps | Docs describe automated flow + recovery and hotfix paths | ## Impact - Automation: reuse `.github/workflows/release-prepare.yml` (phase 1: dry-run, phase 2: publish) and remove `.github/workflows/release-publish.yml` in phase 2. - Package metadata: add `release` script to `package.json`. - Docs: update README or `/docs` to show the automated flow, secrets, guardrails, and recovery steps. ## Acceptance Criteria - Phase 1: merges to `main` open/update a version PR; on merge, the action’s `publish` step is a no-op; no npm publish occurs; logs confirm intended behavior; GitHub releases creation is wired but inert due to no publish. - Phase 2: merges to `main` run `pnpm run release` from the action; npm package publishes successfully; GitHub release is created automatically; `.github/workflows/release-publish.yml` is removed; no duplicate publishes occur. ================================================ FILE: openspec/changes/archive/2025-10-14-update-release-automation/tasks.md ================================================ ## 1. Release workflow automation - [x] 1.1 Add a `.github/workflows/release.yml` that runs on pushes to `main`, sets up pnpm + Node 20, installs dependencies, and invokes `changesets/action@v1` with `publish: pnpm run release`. - [x] 1.2 Configure the action with `createGithubReleases: true` and document required secrets (`NPM_TOKEN`, default `GITHUB_TOKEN`) plus recommended concurrency safeguards. - [x] 1.3 Validate the workflow using `act` or a dry-run push to confirm the action opens release PRs when changesets exist and publishes when the release PR merge lands. ## 2. Package release script - [x] 2.1 Add a `release` script to `package.json` that builds the project and runs `changeset publish` using pnpm. - [x] 2.2 Ensure the script respects the existing `prepare`/`prepublishOnly` hooks to avoid duplicate builds and update documentation or scripts if adjustments are needed. ## 3. Documentation and recovery steps - [x] 3.1 Update maintainer docs (e.g., README or `/docs`) with the end-to-end automated release flow, explicitly removing the manual tag/release steps that are no longer required and explaining how changesets drive the release PR. - [x] 3.2 Document fallback steps for failed publishes (rerun workflow, manual publish) and the hotfix path when a release must be cut without pending changesets. ================================================ FILE: openspec/changes/archive/2025-10-22-add-archive-command-arguments/proposal.md ================================================ # Add Archive Command Arguments ## Why The `/openspec:archive` slash command currently lacks argument support, forcing the AI to infer which change to archive from conversation context or by listing all changes. This creates a safety risk where the wrong proposal could be archived if the context is ambiguous or multiple changes exist. Users expect to specify the change ID explicitly, matching the behavior of the CLI command `openspec archive `. ## What Changes - Add `$ARGUMENTS` placeholder to the OpenCode archive slash command frontmatter (matching existing pattern for proposal command) - Update archive command template steps to validate the specific change ID argument when provided - Note: Codex, GitHub Copilot, and Amazon Q already have `$ARGUMENTS` for archive; Claude/Cursor/Windsurf/Kilocode don't support arguments ## Impact - Affected specs: `cli-update` (slash command generation logic) - Affected code: - `src/core/configurators/slash/opencode.ts` (add `$ARGUMENTS` to archive frontmatter) - `src/core/templates/slash-command-templates.ts` (archive template steps for argument validation) - Breaking: No - this is additive functionality that makes the command safer - User-facing: Yes - OpenCode users will be able to pass the change ID as an argument: `/openspec:archive ` ================================================ FILE: openspec/changes/archive/2025-10-22-add-archive-command-arguments/specs/cli-update/spec.md ================================================ # CLI Update Specification Delta ## MODIFIED Requirements ### Requirement: Slash Command Updates The update command SHALL refresh existing slash command files for configured tools without creating new ones, and ensure the OpenCode archive command accepts change ID arguments. #### Scenario: Updating slash commands for OpenCode - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage - **AND** ensure the archive command includes `$ARGUMENTS` placeholder in frontmatter for accepting change ID arguments ### Requirement: Archive Command Argument Support The archive slash command template SHALL support optional change ID arguments for tools that support `$ARGUMENTS` placeholder. #### Scenario: Archive command with change ID argument - **WHEN** a user invokes `/openspec:archive ` with a change ID - **THEN** the template SHALL instruct the AI to validate the provided change ID against `openspec list` - **AND** use the provided change ID for archiving if valid - **AND** fail fast if the provided change ID doesn't match an archivable change #### Scenario: Archive command without argument (backward compatibility) - **WHEN** a user invokes `/openspec:archive` without providing a change ID - **THEN** the template SHALL instruct the AI to identify the change ID from context or by running `openspec list` - **AND** proceed with the existing behavior (maintaining backward compatibility) #### Scenario: OpenCode archive template generation - **WHEN** generating the OpenCode archive slash command file - **THEN** include the `$ARGUMENTS` placeholder in the frontmatter - **AND** wrap it in a clear structure like `\n $ARGUMENTS\n` to indicate the expected argument - **AND** include validation steps in the template body to check if the change ID is valid ================================================ FILE: openspec/changes/archive/2025-10-22-add-archive-command-arguments/tasks.md ================================================ # Implementation Tasks ## 1. Update OpenCode Configurator - [x] 1.1 Add `$ARGUMENTS` placeholder to OpenCode archive frontmatter (matching the proposal pattern) - [x] 1.2 Format it as `\n $ARGUMENTS\n` or similar structure for clarity - [x] 1.3 Ensure `updateExisting` rewrites the archive frontmatter/body so `$ARGUMENTS` persists after `openspec update` ## 2. Update Slash Command Templates - [x] 2.1 Modify archive steps to validate change ID argument when provided via `$ARGUMENTS` - [x] 2.2 Keep backward compatibility - allow inferring from context if no argument provided - [x] 2.3 Add step to validate the change ID exists using `openspec list` before archiving ## 3. Update Documentation - [x] 3.1 Update AGENTS.md archive examples to show argument usage - [x] 3.2 Document that OpenCode now supports `/openspec:archive ` ================================================ FILE: openspec/changes/archive/2025-10-22-add-cline-support/proposal.md ================================================ ## Why Add support for Cline (VS Code extension) in OpenSpec to enable developers to use Cline's AI-powered coding capabilities for spec-driven development workflows. ## What Changes - Add Cline slash command configurator for proposal, apply, and archive operations - Add Cline root CLINE.md configurator for project-level instructions - Add Cline template exports - Update tool and slash command registries to include Cline - Add comprehensive test coverage - **BREAKING**: None - this is additive functionality ## Impact - Affected specs: cli-init (new tool option) - Affected code: src/core/configurators/slash/cline.ts, src/core/configurators/cline.ts, registry files - New files: .clinerules/openspec-*.md, CLINE.md ================================================ FILE: openspec/changes/archive/2025-10-22-add-cline-support/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: AI Tool Configuration Details The command SHALL properly configure selected AI tools with OpenSpec-specific instructions using a marker system. #### Scenario: Configuring Claude Code - **WHEN** Claude Code is selected - **THEN** create or update `CLAUDE.md` in the project root directory (not inside openspec/) - **AND** populate the managed block with a short stub that points teammates to `@/openspec/AGENTS.md` #### Scenario: Configuring CodeBuddy Code - **WHEN** CodeBuddy Code is selected - **THEN** create or update `CODEBUDDY.md` in the project root directory (not inside openspec/) - **AND** populate the managed block with a short stub that points teammates to `@/openspec/AGENTS.md` #### Scenario: Configuring Cline - **WHEN** Cline is selected - **THEN** create or update `CLINE.md` in the project root directory (not inside openspec/) - **AND** populate the managed block with a short stub that points teammates to `@/openspec/AGENTS.md` #### Scenario: Creating new CLAUDE.md - **WHEN** CLAUDE.md does not exist - **THEN** create new file with stub instructions wrapped in markers so the full workflow stays in `openspec/AGENTS.md`: ```markdown # OpenSpec Instructions This project uses OpenSpec to manage AI assistant workflows. - Full guidance lives in '@/openspec/AGENTS.md'. - Keep this managed block so 'openspec update' can refresh the instructions. ``` ### Requirement: Slash Command Configuration The init command SHALL generate slash command files for supported editors using shared templates. #### Scenario: Generating slash commands for Claude Code - **WHEN** the user selects Claude Code during initialization - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for CodeBuddy Code - **WHEN** the user selects CodeBuddy Code during initialization - **THEN** create `.codebuddy/commands/openspec/proposal.md`, `.codebuddy/commands/openspec/apply.md`, and `.codebuddy/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cline - **WHEN** the user selects Cline during initialization - **THEN** create `.clinerules/openspec-proposal.md`, `.clinerules/openspec-apply.md`, and `.clinerules/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include Cline-specific Markdown heading frontmatter - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cursor - **WHEN** the user selects Cursor during initialization - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for OpenCode - **WHEN** the user selects OpenCode during initialization - **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Windsurf - **WHEN** the user selects Windsurf during initialization - **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Kilo Code - **WHEN** the user selects Kilo Code during initialization - **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Codex - **WHEN** the user selects Codex during initialization - **THEN** create global prompt files at `~/.codex/prompts/openspec-proposal.md`, `~/.codex/prompts/openspec-apply.md`, and `~/.codex/prompts/openspec-archive.md` (or under `$CODEX_HOME/prompts` if set) - **AND** populate each file from shared templates that map the first numbered placeholder (`$1`) to the primary user input (e.g., change identifier or question text) - **AND** wrap the generated content in OpenSpec markers so `openspec update` can refresh the prompts without touching surrounding custom notes #### Scenario: Generating slash commands for GitHub Copilot - **WHEN** the user selects GitHub Copilot during initialization - **THEN** create `.github/prompts/openspec-proposal.prompt.md`, `.github/prompts/openspec-apply.prompt.md`, and `.github/prompts/openspec-archive.prompt.md` - **AND** populate each file with YAML frontmatter containing a `description` field that summarizes the workflow stage - **AND** include `$ARGUMENTS` placeholder to capture user input - **AND** wrap the shared template body with OpenSpec markers so `openspec update` can refresh the content - **AND** each template includes instructions for the relevant OpenSpec workflow stage ================================================ FILE: openspec/changes/archive/2025-10-22-add-cline-support/tasks.md ================================================ ## 1. Implementation - [x] 1.1 Create ClineSlashCommandConfigurator class in src/core/configurators/slash/cline.ts - [x] 1.2 Create ClineConfigurator class in src/core/configurators/cline.ts - [x] 1.3 Create cline-template.ts for template exports - [x] 1.4 Define file paths for Cline rules (.clinerules/) - [x] 1.5 Create Cline-specific frontmatter (Markdown heading format) - [x] 1.6 Register Cline in slash/registry.ts - [x] 1.7 Register Cline in configurators/registry.ts - [x] 1.8 Add Cline to AI_TOOLS in config.ts - [x] 1.9 Add getClineTemplate() to templates/index.ts - [x] 1.10 Update README with Cline documentation ## 2. Testing - [x] 2.1 Add init tests for CLINE.md creation and updates - [x] 2.2 Add init tests for .clinerules/ file creation - [x] 2.3 Add update tests for CLINE.md updates - [x] 2.4 Add update tests for .clinerules/ file refreshes - [x] 2.5 Test integration with openspec init --tools cline - [x] 2.6 Verify all 225 tests pass ================================================ FILE: openspec/changes/archive/2025-10-22-add-crush-support/proposal.md ================================================ ## Why Add support for Crush AI assistant in OpenSpec to enable developers to use Crush's enhanced capabilities for spec-driven development workflows. ## What Changes - Add Crush slash command configurator for proposal, apply, and archive operations - Add Crush-specific AGENTS.md configuration template - Update tool registry to include Crush configurator - **BREAKING**: None - this is additive functionality ## Impact - Affected specs: cli-init (new tool option) - Affected code: src/core/configurators/slash/crush.ts, registry.ts - New files: .crush/commands/openspec/ (proposal.md, apply.md, archive.md) ================================================ FILE: openspec/changes/archive/2025-10-22-add-crush-support/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Slash Command Configuration The init command SHALL generate slash command files for supported editors using shared templates. #### Scenario: Generating slash commands for Claude Code - **WHEN** the user selects Claude Code during initialization - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for CodeBuddy Code - **WHEN** the user selects CodeBuddy Code during initialization - **THEN** create `.codebuddy/commands/openspec/proposal.md`, `.codebuddy/commands/openspec/apply.md`, and `.codebuddy/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cline - **WHEN** the user selects Cline during initialization - **THEN** create `.clinerules/openspec-proposal.md`, `.clinerules/openspec-apply.md`, and `.clinerules/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include Cline-specific Markdown heading frontmatter - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Crush - **WHEN** the user selects Crush during initialization - **THEN** create `.crush/commands/openspec/proposal.md`, `.crush/commands/openspec/apply.md`, and `.crush/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include Crush-specific frontmatter with OpenSpec category and tags - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cursor - **WHEN** the user selects Cursor during initialization - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for OpenCode - **WHEN** the user selects OpenCode during initialization - **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Windsurf - **WHEN** the user selects Windsurf during initialization - **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Kilo Code - **WHEN** the user selects Kilo Code during initialization - **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Codex - **WHEN** the user selects Codex during initialization - **THEN** create global prompt files at `~/.codex/prompts/openspec-proposal.md`, `~/.codex/prompts/openspec-apply.md`, and `~/.codex/prompts/openspec-archive.md` (or under `$CODEX_HOME/prompts` if set) - **AND** populate each file from shared templates that map the first numbered placeholder (`$1`) to the primary user input (e.g., change identifier or question text) - **AND** wrap the generated content in OpenSpec markers so `openspec update` can refresh the prompts without touching surrounding custom notes #### Scenario: Generating slash commands for GitHub Copilot - **WHEN** the user selects GitHub Copilot during initialization - **THEN** create `.github/prompts/openspec-proposal.prompt.md`, `.github/prompts/openspec-apply.prompt.md`, and `.github/prompts/openspec-archive.prompt.md` - **AND** populate each file with YAML frontmatter containing a `description` field that summarizes the workflow stage - **AND** include `$ARGUMENTS` placeholder to capture user input - **AND** wrap the shared template body with OpenSpec markers so `openspec update` can refresh the content - **AND** each template includes instructions for the relevant OpenSpec workflow stage ================================================ FILE: openspec/changes/archive/2025-10-22-add-crush-support/tasks.md ================================================ ## 1. Implementation - [x] 1.1 Create CrushSlashCommandConfigurator class in src/core/configurators/slash/crush.ts - [x] 1.2 Define file paths for Crush commands (.crush/commands/openspec/) - [x] 1.3 Create Crush-specific frontmatter for proposal, apply, archive commands - [x] 1.4 Register Crush configurator in slash/registry.ts - [x] 1.5 Add Crush to available tools in cli-init command - [x] 1.6 Test integration with openspec init --tool crush ================================================ FILE: openspec/changes/archive/2025-10-22-add-factory-slash-commands/proposal.md ================================================ ## Why Factory's Droid CLI recently shipped custom slash commands that mirror other native assistant integrations. Teams using OpenSpec want the same managed workflows they already get for Cursor, Windsurf, and others so init/update can provision and refresh Factory commands without manual setup. ## What Changes - Extend the native tool registry so Factory/Droid appears alongside other slash-command integrations during `openspec init`. - Add shared templates that generate the three Factory custom commands (proposal, apply, archive) and wrap them in OpenSpec markers for safe refreshes. - Update the init and update command flows so they create or refresh Factory command files when the tool is selected or already present. - Refresh CLI specs to document the Factory support and align validation expectations. ## Impact - Affected specs: `specs/cli-init`, `specs/cli-update` - Affected code (expected): tool registry, slash-command template manager, init/update command helpers, documentation snippets ================================================ FILE: openspec/changes/archive/2025-10-22-add-factory-slash-commands/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Slash Command Configuration The init command SHALL generate slash command files for supported editors using shared templates. #### Scenario: Generating slash commands for Claude Code - **WHEN** the user selects Claude Code during initialization - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cursor - **WHEN** the user selects Cursor during initialization - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Factory Droid - **WHEN** the user selects Factory Droid during initialization - **THEN** create `.factory/commands/openspec-proposal.md`, `.factory/commands/openspec-apply.md`, and `.factory/commands/openspec-archive.md` - **AND** populate each file from shared templates that include Factory-compatible YAML frontmatter for the `description` and `argument-hint` fields - **AND** include the `$ARGUMENTS` placeholder in the template body so droid receives any user-supplied input - **AND** wrap the generated content in OpenSpec managed markers so `openspec update` can safely refresh the commands #### Scenario: Generating slash commands for OpenCode - **WHEN** the user selects OpenCode during initialization - **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Windsurf - **WHEN** the user selects Windsurf during initialization - **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Kilo Code - **WHEN** the user selects Kilo Code during initialization - **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Codex - **WHEN** the user selects Codex during initialization - **THEN** create global prompt files at `~/.codex/prompts/openspec-proposal.md`, `~/.codex/prompts/openspec-apply.md`, and `~/.codex/prompts/openspec-archive.md` (or under `$CODEX_HOME/prompts` if set) - **AND** populate each file from shared templates that map the first numbered placeholder (`$1`) to the primary user input (e.g., change identifier or question text) - **AND** wrap the generated content in OpenSpec markers so `openspec update` can refresh the prompts without touching surrounding custom notes #### Scenario: Generating slash commands for GitHub Copilot - **WHEN** the user selects GitHub Copilot during initialization - **THEN** create `.github/prompts/openspec-proposal.prompt.md`, `.github/prompts/openspec-apply.prompt.md`, and `.github/prompts/openspec-archive.prompt.md` - **AND** populate each file with YAML frontmatter containing a `description` field that summarizes the workflow stage - **AND** include `$ARGUMENTS` placeholder to capture user input - **AND** wrap the shared template body with OpenSpec markers so `openspec update` can refresh the content - **AND** each template includes instructions for the relevant OpenSpec workflow stage ================================================ FILE: openspec/changes/archive/2025-10-22-add-factory-slash-commands/specs/cli-update/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Slash Command Updates The update command SHALL refresh existing slash command files for configured tools without creating new ones. #### Scenario: Updating slash commands for Claude Code - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Cursor - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Factory Droid - **WHEN** `.factory/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using the shared Factory templates that include YAML frontmatter for the `description` and `argument-hint` fields - **AND** ensure the template body retains the `$ARGUMENTS` placeholder so user input keeps flowing into droid - **AND** update only the content inside the OpenSpec managed markers, leaving any unmanaged notes untouched - **AND** skip creating missing files during update #### Scenario: Updating slash commands for OpenCode - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Windsurf - **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage - **AND** skip creating missing files (the update command only refreshes what already exists) #### Scenario: Updating slash commands for Kilo Code - **WHEN** `.kilocode/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage - **AND** skip creating missing files (the update command only refreshes what already exists) #### Scenario: Updating slash commands for Codex - **GIVEN** the global Codex prompt directory contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **WHEN** a user runs `openspec update` - **THEN** refresh each file using the shared slash-command templates (including placeholder guidance) - **AND** preserve any unmanaged content outside the OpenSpec marker block - **AND** skip creation when a Codex prompt file is missing #### Scenario: Updating slash commands for GitHub Copilot - **WHEN** `.github/prompts/` contains `openspec-proposal.prompt.md`, `openspec-apply.prompt.md`, and `openspec-archive.prompt.md` - **THEN** refresh each file using shared templates while preserving the YAML frontmatter - **AND** update only the OpenSpec-managed block between markers - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Missing slash command file - **WHEN** a tool lacks a slash command file - **THEN** do not create a new file during update ================================================ FILE: openspec/changes/archive/2025-10-22-add-factory-slash-commands/tasks.md ================================================ ## 1. Factory tool registration - [x] 1.1 Add Factory/Droid metadata to the native tool registry used by init/update (ID, display name, command paths, availability flags). - [x] 1.2 Surface Factory in interactive prompts and non-interactive `--tools` parsing alongside existing slash-command integrations. ## 2. Slash command templates - [x] 2.1 Create shared templates for Factory's `openspec-proposal`, `openspec-apply`, and `openspec-archive` custom commands following Factory's CLI format. - [x] 2.2 Wire the templates into init/update so generation happens on create and refresh respects OpenSpec markers. ## 3. Verification - [x] 3.1 Update or add automated coverage that ensures Factory command files are scaffolded and refreshed correctly. - [x] 3.2 Document the new option in any user-facing copy (help text, README snippets) if required by spec. ================================================ FILE: openspec/changes/archive/2025-11-06-add-shell-completions/design.md ================================================ # Shell Completions Design ## Overview This design establishes a plugin-based architecture for shell completions that prioritizes clean TypeScript patterns, scalability, and maintainability. The system separates concerns between shell-specific generation logic, dynamic completion data providers, and installation automation. **Scope:** This proposal implements **Zsh completion only** (with Oh My Zsh priority). The architecture is designed to support bash, fish, and PowerShell in future proposals. ## Native Shell Completion Behaviors **Design Philosophy:** We integrate with each shell's native completion system rather than attempting to customize or unify behaviors. This ensures familiar UX for users and reduces maintenance complexity. **Note:** While all four shell behaviors are documented below for architectural reference, **only Zsh is implemented in this proposal**. Bash, Fish, and PowerShell are documented to guide future implementations. ### Bash Completion Behavior **Interaction Pattern:** - **Single TAB:** Completes if only one match exists, otherwise does nothing - **Double TAB (TAB TAB):** Displays all possible completions as a list - **Type more characters + TAB:** Narrows matches and completes or shows refined list **OpenSpec Integration:** ```bash # After installing: openspec completion install bash openspec val # Completes to "openspec validate" openspec validate # Shows: --all --changes --specs --strict --json [change-ids] [spec-ids] openspec show add- # Shows all changes starting with "add-" ``` **Implementation:** Uses bash-completion framework with `_init_completion`, `compgen`, and `COMPREPLY` array. ### Zsh Completion Behavior (with Oh My Zsh) **Interaction Pattern:** - **Single TAB:** Shows interactive menu with all matches immediately - **TAB / Arrow Keys:** Navigate through completion options - **Enter:** Selects highlighted option - **Ctrl+C / Esc:** Cancels completion menu **OpenSpec Integration:** ```zsh # After installing: openspec completion install zsh openspec val # Shows menu with "validate" and "view" highlighted openspec show # Shows menu with all change IDs and spec IDs, categorized ``` **Implementation:** Uses Zsh completion system with `_arguments`, `_describe`, and `compadd` built-ins. Oh My Zsh provides enhanced menu styling automatically. ### Fish Completion Behavior **Interaction Pattern:** - **As-you-type:** Gray suggestions appear automatically in real-time - **Right Arrow / Ctrl+F:** Accepts the suggestion - **TAB:** Shows menu with all matches if multiple exist - **TAB again:** Cycles through options or navigates menu - **Enter:** Accepts current selection **OpenSpec Integration:** ```fish # After installing: openspec completion install fish openspec val # Gray suggestion shows "validate" immediately openspec show a # Real-time suggestions for changes starting with "a" openspec # Shows all commands with descriptions in paged menu ``` **Implementation:** Uses Fish's declarative `complete -c` syntax. Completions are auto-loaded from `~/.config/fish/completions/`. ### PowerShell Completion Behavior **Interaction Pattern:** - **TAB:** Cycles forward through completions one at a time (inline replacement) - **Shift+TAB:** Cycles backward through completions - **Ctrl+Space:** Shows IntelliSense-style menu (PSReadLine v2.2+) - **Arrow Keys:** Navigate menu if shown **OpenSpec Integration:** ```powershell # After installing: openspec completion install powershell openspec val # Cycles: validate → view → validate openspec show # Cycles through change IDs one by one openspec # Shows IntelliSense menu with all commands ``` **Implementation:** Uses `Register-ArgumentCompleter` with custom script block that returns `[System.Management.Automation.CompletionResult]` objects. ### Comparison Table | Shell | Trigger | Display Style | Navigation | Selection | |-------------|-----------------|------------------------|----------------------|----------------| | Bash | TAB TAB | List (printed once) | Type more + TAB | Auto-complete | | Zsh | TAB | Interactive menu | TAB/Arrows | Enter | | Fish | TAB/Auto | Real-time + menu | TAB/Arrows | Enter/Right | | PowerShell | TAB | Inline cycling | TAB/Shift+TAB | Stop cycling | **Key Insight:** Each shell's completion UX reflects its design philosophy. We respect these conventions rather than forcing uniformity. ## Architectural Principles ### 1. Plugin-Based Generator System Each shell has unique completion syntax and conventions. Rather than creating a monolithic generator with branching logic, we use a plugin pattern where each shell implements a common interface: ```typescript interface CompletionGenerator { generate(): string; getInstallPath(): string; getConfigFile(): string; } ``` **Benefits:** - New shells can be added without modifying existing generators - Shell-specific logic is isolated and testable - Type safety ensures all generators implement required methods - Easy to maintain and understand (single responsibility per generator) **Implementation Classes:** - `ZshCompletionGenerator` - Uses Zsh's `_arguments` and `_describe` functions - `BashCompletionGenerator` - Uses `_init_completion` and `compgen` built-ins - `FishCompletionGenerator` - Uses `complete -c` declarative syntax - `PowerShellCompletionGenerator` - Uses `Register-ArgumentCompleter` cmdlet ### 2. Centralized Command Registry Shell completions must stay synchronized with actual CLI commands. To avoid duplication and drift, we maintain a single source of truth: ```typescript type CommandDefinition = { name: string; description: string; flags: FlagDefinition[]; acceptsChangeId: boolean; acceptsSpecId: boolean; subcommands?: CommandDefinition[]; }; const COMMAND_REGISTRY: CommandDefinition[] = [ { name: 'init', description: 'Initialize OpenSpec in your project', flags: [ { name: '--tools', description: 'Configure AI tools non-interactively', hasValue: true } ], acceptsChangeId: false, acceptsSpecId: false }, // ... all other commands ]; ``` **Benefits:** - All generators consume the same command definitions - Adding a new command automatically propagates to all shells - Flag changes only need to be made in one place - Type safety prevents typos and missing fields - Easier to test (mock the registry) **TypeScript Sugar:** - Use `const` assertions for readonly registry - Leverage discriminated unions for command types - Use `satisfies` operator to ensure registry matches interface ### 3. Dynamic Completion Provider Change and spec IDs are project-specific and discovered at runtime. A dedicated provider encapsulates this logic: ```typescript class CompletionProvider { private changeCache: { ids: string[]; timestamp: number } | null = null; private specCache: { ids: string[]; timestamp: number } | null = null; private readonly CACHE_TTL_MS = 2000; async getChangeIds(): Promise { if (this.changeCache && Date.now() - this.changeCache.timestamp < this.CACHE_TTL_MS) { return this.changeCache.ids; } const ids = await discoverActiveChangeIds(); this.changeCache = { ids, timestamp: Date.now() }; return ids; } async getSpecIds(): Promise { // Similar caching logic } isOpenSpecProject(): boolean { // Check for openspec/ directory } } ``` **Benefits:** - Caching reduces file system overhead during rapid tab completion - Encapsulates project detection logic - Easy to test with mocked file system - Shared across all shell generators **Design Decisions:** - 2-second cache TTL balances freshness with performance - Cache per-process (not persistent) to avoid stale data across sessions - Graceful degradation when outside OpenSpec projects ### 4. Separate Installation Logic Installation involves shell configuration file manipulation, which differs from generation. We separate this concern: ```typescript interface CompletionInstaller { install(): Promise; uninstall(): Promise; isInstalled(): Promise; } ``` **Shell-Specific Installers:** - `ZshInstaller` - Handles both Oh My Zsh (custom completions) and standard Zsh (fpath) - `BashInstaller` - Detects completion directories and sources from `.bashrc` - `FishInstaller` - Writes to `~/.config/fish/completions/` (auto-loaded) - `PowerShellInstaller` - Appends to PowerShell profile **Benefits:** - Installation logic doesn't pollute generator code - Can test installation without generating completion scripts - Easier to handle edge cases (missing directories, permissions, already installed) ### 5. Type-Safe Shell Detection We use TypeScript's literal types and type guards for shell detection: ```typescript type SupportedShell = 'bash' | 'zsh' | 'fish' | 'powershell'; function detectShell(): SupportedShell { const shellPath = process.env.SHELL || ''; const shellName = path.basename(shellPath).toLowerCase(); // PowerShell normalization if (shellName === 'pwsh' || shellName === 'powershell') { return 'powershell'; } const supported: SupportedShell[] = ['bash', 'zsh', 'fish', 'powershell']; if (supported.includes(shellName as SupportedShell)) { return shellName as SupportedShell; } throw new Error(`Shell '${shellName}' is not supported. Supported: ${supported.join(', ')}`); } ``` **Benefits:** - Compile-time type checking prevents invalid shell names - Easy to add new shells (add to union type) - Type narrowing works in switch statements - Clear error messages for unsupported shells ### 6. Factory Pattern for Instantiation A factory function selects the appropriate generator/installer based on shell type: ```typescript function createGenerator(shell: SupportedShell, provider: CompletionProvider): CompletionGenerator { switch (shell) { case 'bash': return new BashCompletionGenerator(COMMAND_REGISTRY, provider); case 'zsh': return new ZshCompletionGenerator(COMMAND_REGISTRY, provider); case 'fish': return new FishCompletionGenerator(COMMAND_REGISTRY, provider); case 'powershell': return new PowerShellCompletionGenerator(COMMAND_REGISTRY, provider); } } ``` **Benefits:** - Single point of instantiation - Type safety ensures exhaustive switch (TypeScript error if shell type missing) - Easy to inject dependencies (registry, provider) ## Command Structure **This Proposal (Zsh-only):** ``` openspec completion ├── zsh # Generate Zsh completion script ├── install [shell] # Install Zsh completion (auto-detects or explicit zsh) └── uninstall [shell] # Remove Zsh completion (auto-detects or explicit zsh) ``` **Future (after follow-up proposals):** ``` openspec completion ├── bash # Generate Bash completion script (future) ├── zsh # Generate Zsh completion script (this proposal) ├── fish # Generate Fish completion script (future) ├── powershell # Generate PowerShell completion script (future) ├── install [shell] # Install completion (auto-detects or explicit shell) └── uninstall [shell] # Remove completion (auto-detects or explicit shell) ``` ## File Organization **This Proposal (Zsh-only):** ``` src/ ├── commands/ │ └── completion.ts # CLI command registration (zsh, install, uninstall) ├── core/ │ └── completions/ │ ├── types.ts # Interfaces: CompletionGenerator, CommandDefinition, etc. │ ├── command-registry.ts # Single source of truth for OpenSpec commands │ ├── completion-provider.ts # Dynamic change/spec ID discovery with caching │ ├── factory.ts # Factory for instantiating Zsh generator/installer │ ├── generators/ │ │ └── zsh-generator.ts # Zsh completion script generator │ └── installers/ │ └── zsh-installer.ts # Handles Oh My Zsh + standard Zsh installation └── utils/ └── shell-detection.ts # Shell detection (returns 'zsh' or throws) ``` **Future additions (bash, fish, powershell):** - `generators/bash-generator.ts`, `fish-generator.ts`, `powershell-generator.ts` - `installers/bash-installer.ts`, `fish-installer.ts`, `powershell-installer.ts` - Update `shell-detection.ts` to support additional shell types ## Oh My Zsh Priority Zsh implementation prioritizes Oh My Zsh because: 1. **Popularity** - Oh My Zsh is the most popular Zsh configuration framework 2. **Convention** - Has standard completion directory (`~/.oh-my-zsh/custom/completions/`) 3. **Detection** - Easy to detect via `$ZSH` environment variable 4. **Fallback** - Standard Zsh support provides compatibility when Oh My Zsh isn't installed **Installation Strategy:** ```typescript if (isOhMyZshInstalled()) { // Install to ~/.oh-my-zsh/custom/completions/_openspec // Automatically loaded by Oh My Zsh } else { // Install to ~/.zsh/completions/_openspec // Update ~/.zshrc with fpath and compinit if needed } ``` ## Caching Strategy Dynamic completions cache results for 2 seconds to balance freshness with performance: **Why 2 seconds?** - Typical tab completion sessions last < 2 seconds - Prevents repeated file system scans during rapid tabbing - Short enough to feel "live" when changes/specs are added - Automatic per-process expiration (no stale data across sessions) **Implementation:** ```typescript private changeCache: { ids: string[]; timestamp: number } | null = null; private readonly CACHE_TTL_MS = 2000; if (this.changeCache && Date.now() - this.changeCache.timestamp < this.CACHE_TTL_MS) { return this.changeCache.ids; // Use cached } // Refresh cache ``` ## Error Handling Philosophy Completions should degrade gracefully rather than break workflows: 1. **Unsupported shell** - Clear error with list of supported shells 2. **Not in OpenSpec project** - Skip dynamic completions, only offer static commands 3. **Permission errors** - Suggest alternative installation methods 4. **Missing config directories** - Auto-create with user notification 5. **Already installed** - Offer to reinstall/update 6. **Not installed (during uninstall)** - Exit gracefully with informational message ## Testing Strategy Each component is independently testable: 1. **Unit Tests** - Shell detection with mocked `$SHELL` environment variable - Generator output verification (regex pattern matching) - Completion provider caching behavior - Command registry structure validation 2. **Integration Tests** - Installation to temporary test directories - Configuration file modifications - End-to-end command flow (generate → install → verify) 3. **Manual Testing** - Real shell environments (Oh My Zsh, Bash, Fish, PowerShell) - Tab completion behavior in OpenSpec projects - Dynamic change/spec ID suggestions - Installation/uninstallation workflows ## TypeScript Sugar Patterns ### 1. Const Assertions for Immutable Data ```typescript const COMMAND_REGISTRY = [ { name: 'init', ... }, { name: 'list', ... } ] as const; ``` ### 2. Discriminated Unions for Command Types ```typescript type Command = | { type: 'simple'; name: string } | { type: 'with-subcommands'; name: string; subcommands: Command[] }; ``` ### 3. Template Literal Types for Strings ```typescript type ShellConfigFile = `~/.${SupportedShell}rc` | `~/.${SupportedShell}_profile`; ``` ### 4. Satisfies Operator for Type Validation ```typescript const config = { shell: 'zsh', path: '~/.zshrc' } satisfies ShellConfig; ``` ### 5. Optional Chaining and Nullish Coalescing ```typescript const path = process.env.ZSH ?? `${os.homedir()}/.oh-my-zsh`; ``` ### 6. Async/Await with Promise.all for Parallel Operations ```typescript const [changes, specs] = await Promise.all([ provider.getChangeIds(), provider.getSpecIds() ]); ``` ## Scalability Considerations ### Adding a New Shell 1. Define shell in `SupportedShell` union type 2. Create generator class implementing `CompletionGenerator` 3. Create installer class implementing `CompletionInstaller` 4. Add cases to factory functions 5. Add command registration in CLI 6. Write tests **TypeScript will enforce** that all switch statements are updated (exhaustiveness checking). ### Adding a New Command 1. Add to `COMMAND_REGISTRY` with appropriate metadata 2. All generators automatically include it 3. Update tests to verify new command appears ### Changing Completion Behavior Dynamic completion logic is centralized in `CompletionProvider`, making behavior changes trivial without touching shell-specific code. ## Trade-offs and Decisions ### Decision: Separate Generators vs. Template Engine **Chosen:** Separate generator classes per shell **Alternative:** Template engine with shell-specific templates **Rationale:** - Shell completion syntax is fundamentally different (not just text substitution) - Type safety is better with classes than templates - Logic complexity (caching, dynamic completions) doesn't fit template paradigm - Easier to debug and test dedicated classes ### Decision: 2-Second Cache TTL **Chosen:** 2-second cache **Alternatives:** No cache (slow), longer cache (stale), persistent cache (complex) **Rationale:** - Balances performance with freshness - Matches typical user interaction patterns - Simple implementation (no invalidation complexity) - Automatic cleanup on process exit ### Decision: Oh My Zsh Detection **Chosen:** Check `$ZSH` env var first, then `~/.oh-my-zsh/` directory **Rationale:** - `$ZSH` is set by Oh My Zsh initialization (reliable) - Directory check is fallback for non-interactive scenarios - Standard Zsh serves as ultimate fallback ### Decision: Installation Automation vs. Manual Instructions **Chosen:** Automated installation with install/uninstall commands **Alternative:** Generate script and provide manual installation instructions **Rationale:** - Better user experience (one command vs. multiple manual steps) - Reduces errors from manual configuration - Aligns with user expectations for modern CLI tools - Still supports manual workflow via script generation to stdout ## Future Enhancements 1. **Contextual Flag Completion** - Suggest only valid flags for current command 2. **Fuzzy Matching** - Allow partial matching for change/spec IDs 3. **Rich Descriptions** - Include "why" section in completion suggestions (shell-dependent) 4. **Completion Stats** - Track completion usage for analytics 5. **Custom Completion Hooks** - Allow projects to extend completions 6. **MCP Integration** - Provide completions via Model Context Protocol ## References - [Bash Programmable Completion](https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html) - [Zsh Completion System](https://zsh.sourceforge.io/Doc/Release/Completion-System.html) - [Fish Completions](https://fishshell.com/docs/current/completions.html) - [PowerShell Argument Completers](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/register-argumentcompleter) - [Oh My Zsh Custom Completions](https://github.com/ohmyzsh/ohmyzsh/wiki/Customization#adding-custom-completions) ================================================ FILE: openspec/changes/archive/2025-11-06-add-shell-completions/proposal.md ================================================ # Add Shell Completions ## Why OpenSpec CLI commands lack shell completion, forcing users to remember all commands, subcommands, flags, and change/spec IDs manually. This creates friction during daily use and slows developer workflows. Shell completions are a standard expectation for modern CLI tools and significantly improve user experience through: - Faster command discovery via tab completion - Reduced cognitive load by removing memorization requirements - Fewer typos through validated suggestions - Professional polish expected of production-grade tools ## What Changes This change adds shell completion support for the OpenSpec CLI, starting with **Zsh (including Oh My Zsh)** and establishing a scalable architecture for future shells (bash, fish, PowerShell). The implementation provides: 1. **New `openspec completion` command** with Zsh generation and installation/uninstallation capabilities 2. **Native Zsh integration** that respects standard Zsh tab completion behavior (single-TAB menu navigation) 3. **Dynamic completion providers** that discover active changes and specs from the current project 4. **Plugin-based architecture** using TypeScript interfaces for easy extension to additional shells in future proposals 5. **Installation automation** for Oh My Zsh (priority) and standard Zsh configurations 6. **Context-aware suggestions** that only activate within OpenSpec-enabled projects The architecture emphasizes clean TypeScript patterns, composable generators, separation of concerns between shell-specific logic and shared completion data providers, and integration with native shell completion systems. Other shells (bash, fish, PowerShell) are architecturally documented but not implemented in this proposal—they will be added in follow-up changes. ## Deltas ### Delta: New CLI completion specification - **Spec:** cli-completion - **Operation:** ADDED - **Description:** Defines requirements for the new `openspec completion` command including generation, installation, and shell-specific behaviors for Oh My Zsh, bash, fish, and PowerShell. ================================================ FILE: openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md ================================================ # CLI Completion Specification ## Purpose The `openspec completion` command SHALL provide shell completion functionality for all OpenSpec CLI commands, flags, and dynamic values (change IDs, spec IDs), with support for Zsh (including Oh My Zsh) and a scalable architecture ready for future shells (bash, fish, PowerShell). The completion system SHALL integrate with Zsh's native completion behavior rather than attempting to customize the user experience. ## ADDED Requirements ### Requirement: Native Shell Behavior Integration The completion system SHALL respect and integrate with Zsh's native completion patterns and user interaction model. #### Scenario: Zsh native completion - **WHEN** generating Zsh completion scripts - **THEN** use Zsh completion system with `_arguments`, `_describe`, and `compadd` - **AND** completions SHALL trigger on single TAB (standard Zsh behavior) - **AND** display as an interactive menu that users navigate with TAB/arrow keys - **AND** support Oh My Zsh's enhanced menu styling automatically #### Scenario: No custom UX patterns - **WHEN** implementing Zsh completion - **THEN** do NOT attempt to customize completion trigger behavior - **AND** do NOT override Zsh-specific navigation patterns - **AND** ensure completions feel native to experienced Zsh users ### Requirement: Command Structure The completion command SHALL follow a subcommand pattern for generating and managing completion scripts. #### Scenario: Available subcommands - **WHEN** user executes `openspec completion --help` - **THEN** display available subcommands: - `zsh` - Generate Zsh completion script - `install [shell]` - Install completion for Zsh (auto-detects or requires explicit shell) - `uninstall [shell]` - Remove completion for Zsh (auto-detects or requires explicit shell) ### Requirement: Shell Detection The completion system SHALL automatically detect the user's current shell environment. #### Scenario: Detecting Zsh from environment - **WHEN** no shell is explicitly specified - **THEN** read the `$SHELL` environment variable - **AND** extract the shell name from the path (e.g., `/bin/zsh` → `zsh`) - **AND** validate the shell is `zsh` - **AND** throw an error if the shell is not `zsh`, with message indicating only Zsh is currently supported #### Scenario: Non-Zsh shell detection - **WHEN** shell path indicates bash, fish, powershell, or other non-Zsh shell - **THEN** throw error: "Shell '' is not supported yet. Currently supported: zsh" ### Requirement: Completion Generation The completion command SHALL generate Zsh completion scripts on demand. #### Scenario: Generating Zsh completion - **WHEN** user executes `openspec completion zsh` - **THEN** output a complete Zsh completion script to stdout - **AND** include completions for all commands: init, list, show, validate, archive, view, update, change, spec, completion - **AND** include all command-specific flags and options - **AND** use Zsh's `_arguments` and `_describe` built-in functions - **AND** support dynamic completion for change and spec IDs ### Requirement: Dynamic Completions The completion system SHALL provide context-aware dynamic completions for project-specific values. #### Scenario: Completing change IDs - **WHEN** completing arguments for commands that accept change names (show, validate, archive) - **THEN** discover active changes from `openspec/changes/` directory - **AND** exclude archived changes in `openspec/changes/archive/` - **AND** return change IDs as completion suggestions - **AND** only provide suggestions when inside an OpenSpec-enabled project #### Scenario: Completing spec IDs - **WHEN** completing arguments for commands that accept spec names (show, validate) - **THEN** discover specs from `openspec/specs/` directory - **AND** return spec IDs as completion suggestions - **AND** only provide suggestions when inside an OpenSpec-enabled project #### Scenario: Completion caching - **WHEN** dynamic completions are requested - **THEN** cache discovered change and spec IDs for 2 seconds - **AND** reuse cached values for subsequent requests within cache window - **AND** automatically refresh cache after expiration #### Scenario: Project detection - **WHEN** user requests completions outside an OpenSpec project - **THEN** skip dynamic change/spec ID completions - **AND** only suggest static commands and flags ### Requirement: Installation Automation The completion command SHALL automatically install completion scripts into shell configuration files. #### Scenario: Installing for Oh My Zsh - **WHEN** user executes `openspec completion install zsh` - **THEN** detect if Oh My Zsh is installed by checking for `$ZSH` environment variable or `~/.oh-my-zsh/` directory - **AND** create custom completions directory at `~/.oh-my-zsh/custom/completions/` if it doesn't exist - **AND** write completion script to `~/.oh-my-zsh/custom/completions/_openspec` - **AND** ensure `~/.oh-my-zsh/custom/completions` is in `$fpath` by updating `~/.zshrc` if needed - **AND** display success message with instruction to run `exec zsh` or restart terminal #### Scenario: Installing for standard Zsh - **WHEN** user executes `openspec completion install zsh` and Oh My Zsh is not detected - **THEN** create completions directory at `~/.zsh/completions/` if it doesn't exist - **AND** write completion script to `~/.zsh/completions/_openspec` - **AND** add `fpath=(~/.zsh/completions $fpath)` to `~/.zshrc` if not already present - **AND** add `autoload -Uz compinit && compinit` to `~/.zshrc` if not already present - **AND** display success message with instruction to run `exec zsh` or restart terminal #### Scenario: Auto-detecting Zsh for installation - **WHEN** user executes `openspec completion install` without specifying a shell - **THEN** detect current shell using shell detection logic - **AND** install completion if detected shell is Zsh - **AND** throw error if detected shell is not Zsh - **AND** display which shell was detected #### Scenario: Already installed - **WHEN** completion is already installed for the target shell - **THEN** display message indicating completion is already installed - **AND** offer to reinstall/update by overwriting existing files - **AND** exit with code 0 ### Requirement: Uninstallation The completion command SHALL remove installed completion scripts and configuration. #### Scenario: Uninstalling Oh My Zsh completion - **WHEN** user executes `openspec completion uninstall zsh` - **THEN** remove `~/.oh-my-zsh/custom/completions/_openspec` if Oh My Zsh is detected - **AND** remove `~/.zsh/completions/_openspec` if standard Zsh setup is detected - **AND** optionally remove fpath modifications from `~/.zshrc` (with confirmation) - **AND** display success message #### Scenario: Auto-detecting Zsh for uninstallation - **WHEN** user executes `openspec completion uninstall` without specifying a shell - **THEN** detect current shell and uninstall completion if shell is Zsh - **AND** throw error if detected shell is not Zsh #### Scenario: Not installed - **WHEN** attempting to uninstall completion that isn't installed - **THEN** display message indicating completion is not installed - **AND** exit with code 0 ### Requirement: Architecture Patterns The completion implementation SHALL follow clean architecture principles with TypeScript best practices. #### Scenario: Shell-specific generators - **WHEN** implementing completion generators - **THEN** create `ZshCompletionGenerator` class for Zsh - **AND** implement a common `CompletionGenerator` interface with methods: - `generate(): string` - Returns complete shell script - `getInstallPath(): string` - Returns target installation path - `getConfigFile(): string` - Returns shell configuration file path - **AND** design interface to be extensible for future shells (bash, fish, powershell) #### Scenario: Dynamic completion providers - **WHEN** implementing dynamic completions - **THEN** create a `CompletionProvider` class that encapsulates project discovery logic - **AND** implement methods: - `getChangeIds(): Promise` - Discovers active change IDs - `getSpecIds(): Promise` - Discovers spec IDs - `isOpenSpecProject(): boolean` - Checks if current directory is OpenSpec-enabled - **AND** implement caching with 2-second TTL using class properties #### Scenario: Command registry - **WHEN** defining completable commands - **THEN** create a centralized `CommandDefinition` type with properties: - `name: string` - Command name - `description: string` - Help text - `flags: FlagDefinition[]` - Available flags - `acceptsChangeId: boolean` - Whether command takes change ID argument - `acceptsSpecId: boolean` - Whether command takes spec ID argument - `subcommands?: CommandDefinition[]` - Nested subcommands - **AND** export a `COMMAND_REGISTRY` constant with all command definitions - **AND** generators consume this registry to ensure consistency #### Scenario: Type-safe shell detection - **WHEN** implementing shell detection - **THEN** define a `SupportedShell` type as literal type: `'zsh'` - **AND** implement `detectShell()` function that returns 'zsh' or throws error - **AND** design type to be extensible (e.g., future: `'bash' | 'zsh' | 'fish' | 'powershell'`) ### Requirement: Error Handling The completion command SHALL provide clear error messages for common failure scenarios. #### Scenario: Unsupported shell - **WHEN** user requests completion for unsupported shell (bash, fish, powershell, etc.) - **THEN** display error message: "Shell '' is not supported yet. Currently supported: zsh" - **AND** exit with code 1 #### Scenario: Permission errors during installation - **WHEN** installation fails due to file permission issues - **THEN** display clear error message indicating permission problem - **AND** suggest using appropriate permissions or alternative installation method - **AND** exit with code 1 #### Scenario: Missing shell configuration directory - **WHEN** expected shell configuration directory doesn't exist - **THEN** create the directory automatically (with user notification) - **AND** proceed with installation #### Scenario: Shell not detected - **WHEN** `openspec completion install` cannot detect current shell or detects non-Zsh shell - **THEN** display error: "Could not detect Zsh. Please specify explicitly: openspec completion install zsh" - **AND** exit with code 1 ### Requirement: Output Format The completion command SHALL provide machine-parseable and human-readable output. #### Scenario: Script generation output - **WHEN** generating completion script to stdout - **THEN** output only the completion script content (no extra messages) - **AND** allow redirection to files: `openspec completion zsh > /path/to/_openspec` #### Scenario: Installation success output - **WHEN** installation completes successfully - **THEN** display formatted success message with: - Checkmark indicator - Installation location - Next steps (shell reload instructions) - **AND** use colors when terminal supports it (unless `--no-color` is set) #### Scenario: Verbose installation output - **WHEN** user provides `--verbose` flag during installation - **THEN** display detailed steps: - Shell detection result - Target file paths - Configuration modifications - File creation confirmations ### Requirement: Testing Support The completion implementation SHALL be testable with unit and integration tests. #### Scenario: Mock shell environment - **WHEN** writing tests for shell detection - **THEN** allow overriding `$SHELL` environment variable - **AND** use dependency injection for file system operations #### Scenario: Generator output verification - **WHEN** testing completion generators - **THEN** verify generated scripts contain expected patterns - **AND** test that command registry is properly consumed - **AND** ensure dynamic completion placeholders are present #### Scenario: Installation simulation - **WHEN** testing installation logic - **THEN** use temporary test directories instead of actual home directories - **AND** verify file creation without modifying real shell configurations - **AND** test path resolution logic independently ## Not in Scope The following shells are **architecturally documented but not implemented** in this proposal. They will be added in future proposals: - **Bash completion** - Will use bash-completion framework with `_init_completion`, `compgen`, and `COMPREPLY` - **Fish completion** - Will use Fish's declarative `complete -c` syntax - **PowerShell completion** - Will use `Register-ArgumentCompleter` with completion result objects The plugin-based architecture (CompletionGenerator interface, command registry, dynamic providers) is designed to make adding these shells straightforward in follow-up changes. ## Why Shell completions are essential for professional CLI tools and significantly improve developer experience by reducing friction, errors, and cognitive load during daily workflows. ================================================ FILE: openspec/changes/archive/2025-11-06-add-shell-completions/tasks.md ================================================ # Implementation Tasks ## Phase 1: Foundation & Architecture - [x] Create `src/utils/shell-detection.ts` with `SupportedShell` type and `detectShell()` function - [x] Create `src/core/completions/types.ts` with interfaces: `CompletionGenerator`, `CommandDefinition`, `FlagDefinition` - [x] Create `src/core/completions/command-registry.ts` with `COMMAND_REGISTRY` constant defining all OpenSpec commands, flags, and metadata - [x] Create `src/core/completions/completion-provider.ts` with `CompletionProvider` class for dynamic change/spec ID discovery with 2-second caching - [x] Write tests for shell detection (`test/utils/shell-detection.test.ts`) - [x] Write tests for completion provider (`test/core/completions/completion-provider.test.ts`) ## Phase 2: Zsh Completion (Oh My Zsh Priority) - [x] Create `src/core/completions/generators/zsh-generator.ts` implementing `CompletionGenerator` interface - [x] Implement Zsh script generation using `_arguments` and `_describe` patterns - [x] Add dynamic completion logic for change/spec IDs using completion provider - [x] Test Zsh generator output (`test/core/completions/generators/zsh-generator.test.ts`) - [x] Create `src/core/completions/installers/zsh-installer.ts` with Oh My Zsh and standard Zsh support - [x] Implement Oh My Zsh detection (`$ZSH` env var or `~/.oh-my-zsh/` directory) - [x] Implement installation to `~/.oh-my-zsh/custom/completions/_openspec` for Oh My Zsh - [x] Implement fallback installation to `~/.zsh/completions/_openspec` with `fpath` updates - [x] Test Zsh installer logic with mocked file system (`test/core/completions/installers/zsh-installer.test.ts`) ## Phase 3: CLI Command Implementation - [x] Create `src/commands/completion.ts` with `CompletionCommand` class - [x] Register `completion` command in `src/cli/index.ts` with subcommands: generate, install, uninstall - [x] Implement `generateSubcommand()` that outputs Zsh script to stdout - [x] Implement `installSubcommand(shell?: 'zsh')` with auto-detection for Zsh-only - [x] Implement `uninstallSubcommand(shell?: 'zsh')` for removing Zsh completions - [x] Add `--verbose` flag support for detailed installation output - [x] Add error handling with clear messages: "Shell '' is not supported yet. Currently supported: zsh" - [x] Test completion command integration (`test/commands/completion.test.ts`) ## Phase 4: Integration & Polish - [x] Create factory pattern in `src/core/completions/factory.ts` to instantiate Zsh generator/installer (extensible for future shells) - [x] Add `completion` command to command registry for self-referential completion - [x] Implement dynamic completion helper functions in Zsh generator (`_openspec_complete_changes`, `_openspec_complete_specs`, `_openspec_complete_items`) - [x] Add 'shell' positional type for completion command arguments - [x] Test completion generation with dynamic helpers - [x] Test completion install/uninstall flow - [x] Verify all tests pass (97 completion tests, 340 total tests) - [x] Implement auto-install via npm postinstall script - [x] Add safety checks (CI detection, opt-out flag) - [x] Handle Oh My Zsh vs standard Zsh installation paths - [x] Add test script for postinstall validation - [x] Document auto-install behavior and opt-out in README - [ ] Manually test Zsh completion in Oh My Zsh environment (install, test tab completion, uninstall) - [ ] Manually test Zsh completion in standard Zsh environment - [ ] Test dynamic change/spec ID completion in real OpenSpec projects - [ ] Verify completion cache behavior (2-second TTL) - [ ] Test behavior outside OpenSpec projects (should skip dynamic completions) - [x] Update `openspec --help` output to include completion command (automatically done via Commander) ## Phase 5: Edge Cases & Error Handling - [ ] Test and handle permission errors during installation - [ ] Test and handle missing shell configuration directories (auto-create with notification) - [ ] Test "already installed" detection and reinstall flow - [ ] Test "not installed" detection during uninstall - [ ] Verify `--no-color` flag is respected in completion command output - [ ] Test shell detection failure scenarios with helpful error messages - [ ] Ensure graceful handling when `$SHELL` is unset or invalid - [ ] Test non-Zsh shells get clear "not supported yet" error messages - [ ] Test generator output can be redirected to files without corruption ## Dependencies - Phase 2 depends on Phase 1 (foundation must exist first) - Phase 3 depends on Phase 2 (CLI needs Zsh generator working) - Phase 4 depends on Phase 3 (integration requires CLI + Zsh implementation) - Phase 5 depends on Phase 4 (edge case testing after core functionality works) ## Future Work (Not in This Proposal) - **Bash completions** - Create bash-generator.ts and bash-installer.ts in follow-up proposal - **Fish completions** - Create fish-generator.ts and fish-installer.ts in follow-up proposal - **PowerShell completions** - Create powershell-generator.ts and powershell-installer.ts in follow-up proposal The architecture is designed to make adding these shells straightforward by implementing the `CompletionGenerator` interface. ================================================ FILE: openspec/changes/archive/2025-12-20-add-global-config-dir/design.md ================================================ ## Context OpenSpec needs a standard location for user-level configuration that works across platforms and follows established conventions. This will serve as the foundation for settings, feature flags, and future artifacts like workflows or templates. ## Goals / Non-Goals **Goals:** - Provide a single, well-defined location for global config - Follow XDG Base Directory Specification (widely adopted by CLI tools) - Support cross-platform usage (Unix, macOS, Windows) - Keep implementation minimal - just the foundation - Enable future expansion (cache, state, workflows) **Non-Goals:** - Project-local config override (not in scope) - Config file migration tooling - Config validation CLI commands - Multiple config profiles ## Decisions ### Path Resolution Strategy **Decision:** Use XDG Base Directory Specification with platform fallbacks. ``` Unix/macOS: $XDG_CONFIG_HOME/openspec/ or ~/.config/openspec/ Windows: %APPDATA%/openspec/ ``` **Rationale:** - XDG is the de facto standard for CLI tools (used by gh, bat, ripgrep, etc.) - Environment variable override allows user customization - Windows uses its native convention (%APPDATA%) for better integration **Alternatives considered:** - `~/.openspec/` - Simple but clutters home directory - `~/Library/Application Support/` on macOS - Overkill for a CLI tool ### Config File Format **Decision:** JSON (`config.json`) **Rationale:** - Native Node.js support (no dependencies) - Human-readable and editable - Type-safe with TypeScript - Matches project.md's "minimal dependencies" principle **Alternatives considered:** - YAML - Requires dependency, more error-prone to edit - TOML - Less common in Node.js ecosystem - Environment variables only - Too limited for structured settings ### Config Schema **Decision:** Flat structure with typed fields, start minimal. ```typescript interface GlobalConfig { featureFlags?: Record; } ``` **Rationale:** - `featureFlags` enables controlled rollout of new features - Optional fields with defaults avoid breaking changes - Flat structure is easy to understand and extend ### Loading Strategy **Decision:** Read from disk on each call, no caching. ```typescript export function getGlobalConfig(): GlobalConfig { return loadConfigFromDisk(); } ``` **Rationale:** - CLI commands are short-lived; caching adds complexity without benefit - Reading a small JSON file is ~1ms; negligible overhead - Always returns fresh data; no cache invalidation concerns - Simpler implementation ### Directory Creation **Decision:** Create directory only when saving, not when reading. **Rationale:** - Don't create empty directories on read operations - Users who never save config won't have unnecessary directories - Aligns with principle of least surprise ## Risks / Trade-offs | Risk | Mitigation | |------|------------| | Config file corruption | Return defaults on parse error, log warning | | Permissions issues | Check write permissions before save, clear error message | | Future schema changes | Use optional fields, add version field if needed later | ## Open Questions None - this proposal is intentionally minimal. ================================================ FILE: openspec/changes/archive/2025-12-20-add-global-config-dir/proposal.md ================================================ ## Why OpenSpec currently has no mechanism for user-level global settings or feature flags. As the CLI grows, we need a standard location to store user preferences, experimental features, and other configuration that persists across projects. Following XDG Base Directory Specification provides a well-understood, cross-platform approach. ## What Changes - Add new `src/core/global-config.ts` module with: - Path resolution following XDG Base Directory spec (`$XDG_CONFIG_HOME/openspec/` or fallback) - Cross-platform support (Unix, macOS, Windows) - Lazy config loading with sensible defaults - TypeScript types for config shape - Export a global config directory path getter for future use (workflows, templates, cache) - Initial config schema supports 1-2 settings/feature flags only ## Impact - Affected specs: New `global-config` capability (no existing specs modified) - Affected code: - New `src/core/global-config.ts` - Update `src/core/index.ts` to export new module ================================================ FILE: openspec/changes/archive/2025-12-20-add-global-config-dir/specs/global-config/spec.md ================================================ ## ADDED Requirements ### Requirement: Global Config Directory Path The system SHALL resolve the global configuration directory path following XDG Base Directory Specification with platform-specific fallbacks. #### Scenario: Unix/macOS with XDG_CONFIG_HOME set - **WHEN** `$XDG_CONFIG_HOME` environment variable is set to `/custom/config` - **THEN** `getGlobalConfigDir()` returns `/custom/config/openspec` #### Scenario: Unix/macOS without XDG_CONFIG_HOME - **WHEN** `$XDG_CONFIG_HOME` environment variable is not set - **AND** the platform is Unix or macOS - **THEN** `getGlobalConfigDir()` returns `~/.config/openspec` (expanded to absolute path) #### Scenario: Windows platform - **WHEN** the platform is Windows - **AND** `%APPDATA%` is set to `C:\Users\User\AppData\Roaming` - **THEN** `getGlobalConfigDir()` returns `C:\Users\User\AppData\Roaming\openspec` ### Requirement: Global Config Loading The system SHALL load global configuration from the config directory with sensible defaults when the config file does not exist or cannot be parsed. #### Scenario: Config file exists and is valid - **WHEN** `config.json` exists in the global config directory - **AND** the file contains valid JSON matching the config schema - **THEN** `getGlobalConfig()` returns the parsed configuration #### Scenario: Config file does not exist - **WHEN** `config.json` does not exist in the global config directory - **THEN** `getGlobalConfig()` returns the default configuration - **AND** no directory or file is created #### Scenario: Config file is invalid JSON - **WHEN** `config.json` exists but contains invalid JSON - **THEN** `getGlobalConfig()` returns the default configuration - **AND** a warning is logged to stderr ### Requirement: Global Config Saving The system SHALL save global configuration to the config directory, creating the directory if it does not exist. #### Scenario: Save config to new directory - **WHEN** `saveGlobalConfig(config)` is called - **AND** the global config directory does not exist - **THEN** the directory is created - **AND** `config.json` is written with the provided configuration #### Scenario: Save config to existing directory - **WHEN** `saveGlobalConfig(config)` is called - **AND** the global config directory already exists - **THEN** `config.json` is written (overwriting if exists) ### Requirement: Default Configuration The system SHALL provide a default configuration that is used when no config file exists. #### Scenario: Default config structure - **WHEN** no config file exists - **THEN** the default configuration includes an empty `featureFlags` object ### Requirement: Config Schema Evolution The system SHALL merge loaded configuration with default values to ensure new config fields are available even when loading older config files. #### Scenario: Config file missing new fields - **WHEN** `config.json` exists with `{ "featureFlags": {} }` - **AND** the current schema includes a new field `defaultAiTool` - **THEN** `getGlobalConfig()` returns `{ featureFlags: {}, defaultAiTool: }` - **AND** the loaded values take precedence over defaults for fields that exist in both #### Scenario: Config file has extra unknown fields - **WHEN** `config.json` contains fields not in the current schema - **THEN** the unknown fields are preserved in the returned configuration - **AND** no error or warning is raised ================================================ FILE: openspec/changes/archive/2025-12-20-add-global-config-dir/tasks.md ================================================ ## 1. Core Implementation - [x] 1.1 Create `src/core/global-config.ts` with path resolution - Implement `getGlobalConfigDir()` following XDG spec - Support `$XDG_CONFIG_HOME` environment variable override - Platform-specific fallbacks (Unix: `~/.config/`, Windows: `%APPDATA%`) - [x] 1.2 Define TypeScript interfaces for config shape - `GlobalConfig` interface with optional fields - Start minimal: just `featureFlags?: Record` - [x] 1.3 Implement config loading with defaults - `getGlobalConfig()` - reads config.json if exists, merges with defaults - No directory/file creation on read (lazy initialization) - [x] 1.4 Implement config saving - `saveGlobalConfig(config)` - writes config.json, creates directory if needed ## 2. Integration - [x] 2.1 Export new module from `src/core/index.ts` - [x] 2.2 Add constants for config file name and directory name ## 3. Testing - [x] 3.1 Manual testing of path resolution on current platform - [x] 3.2 Test with/without `$XDG_CONFIG_HOME` set - [x] 3.3 Test config load when file doesn't exist (should return defaults) - [x] 3.4 Unit tests in `test/core/global-config.test.ts` (18 tests) ================================================ FILE: openspec/changes/archive/2025-12-21-add-config-command/design.md ================================================ ## Context The `global-config` spec defines how OpenSpec reads/writes `config.json`, but users currently must edit it by hand. This command provides a CLI interface to that config. ## Goals / Non-Goals **Goals:** - Provide a discoverable CLI for config management - Support scripting with machine-readable output - Validate config changes with zod schema - Handle nested keys gracefully **Non-Goals:** - Project-local config (reserved for future via `--scope` flag) - Complex queries (JSONPath, filtering) - Config file format migration ## Decisions ### Key Naming: camelCase with Dot Notation **Decision:** Keys use camelCase matching the JSON structure, with dot notation for nesting. **Rationale:** - Matches the actual JSON keys (no translation layer) - Dot notation is intuitive and widely used (lodash, jq, kubectl) - Avoids complexity of supporting multiple casing styles **Examples:** ```bash openspec config get featureFlags # Returns object openspec config get featureFlags.experimental # Returns nested value openspec config set featureFlags.newFlag true ``` ### Type Coercion: Auto-detect with `--string` Override **Decision:** Parse values automatically; provide `--string` flag to force string storage. **Rationale:** - Most intuitive for common cases (`true`, `false`, `123`) - Explicit override for edge cases (storing literal string "true") - Follows npm/yarn config patterns **Coercion rules:** | Input | Stored As | |-------|-----------| | `true`, `false` | boolean | | Numeric string (`123`, `3.14`) | number | | Everything else | string | | Any value with `--string` | string | ### Output Format: Raw by Default **Decision:** `get` prints raw value only. `list` prints YAML-like format by default, JSON with `--json`. **Rationale:** - Raw output enables piping: `VAR=$(openspec config get key)` - YAML-like is human-readable for inspection - JSON for automation/scripting ### Schema Validation: Zod with Unknown Field Passthrough **Decision:** Use zod for validation but preserve unknown fields per `global-config` spec. **Rationale:** - Type safety for known fields - Forward compatibility (old CLI doesn't break new config) - Follows existing `global-config` spec requirement ### Reserved Flag: `--scope` **Decision:** Reserve `--scope global|project` but only implement `global` initially. **Rationale:** - Avoids breaking change if project-local config is added later - Clear error message if someone tries `--scope project` ## Risks / Trade-offs | Risk | Mitigation | |------|------------| | Dot notation conflicts with keys containing dots | Rare in practice; document limitation | | Type coercion surprises | `--string` escape hatch; document rules | | $EDITOR not set | Check and provide helpful error message | ## Open Questions None - design is straightforward. ================================================ FILE: openspec/changes/archive/2025-12-21-add-config-command/proposal.md ================================================ ## Why Users need a way to view and modify their global OpenSpec settings without manually editing JSON files. The `global-config` spec provides the foundation, but there's no user-facing interface to interact with the config. A dedicated `openspec config` command provides discoverability and ease of use. ## What Changes Add `openspec config` subcommand with the following operations: ```bash openspec config path # Show config file location openspec config list [--json] # Show all current settings openspec config get # Get a specific value (raw, scriptable) openspec config set [--string] # Set a value (auto-coerce types) openspec config unset # Remove a key (revert to default) openspec config reset --all [-y] # Reset everything to defaults openspec config edit # Open config in $EDITOR ``` **Key design decisions:** - **Key naming**: Use camelCase to match JSON structure (e.g., `featureFlags.someFlag`) - **Nested keys**: Support dot notation for nested access - **Type coercion**: Auto-detect types by default; `--string` flag forces string storage - **Scriptable output**: `get` prints raw value only (no labels) for easy piping - **Zod validation**: Use zod for config schema validation and type safety - **Future-proofing**: Reserve `--scope global|project` flag for potential project-local config **Example usage:** ```bash $ openspec config path /Users/me/.config/openspec/config.json $ openspec config list featureFlags: {} $ openspec config set featureFlags.enableTelemetry false Set featureFlags.enableTelemetry = false $ openspec config get featureFlags.enableTelemetry false $ openspec config list --json { "featureFlags": {} } $ openspec config unset featureFlags.enableTelemetry Unset featureFlags.enableTelemetry (reverted to default) $ openspec config edit # Opens $EDITOR with config.json ``` ## Impact - Affected specs: New `cli-config` capability - Affected code: - New `src/commands/config.ts` - New `src/core/config-schema.ts` (zod schema) - Update CLI entry point to register config command - Dependencies: Requires `global-config` spec (already implemented) ================================================ FILE: openspec/changes/archive/2025-12-21-add-config-command/specs/cli-config/spec.md ================================================ # cli-config Specification ## Purpose Provide a CLI interface for viewing and modifying global OpenSpec configuration. Enables users to manage settings without manually editing JSON files, with support for scripting and automation. ## ADDED Requirements ### Requirement: Command Structure The config command SHALL provide subcommands for all configuration operations. #### Scenario: Available subcommands - **WHEN** user executes `openspec config --help` - **THEN** display available subcommands: - `path` - Show config file location - `list` - Show all current settings - `get ` - Get a specific value - `set ` - Set a value - `unset ` - Remove a key (revert to default) - `reset` - Reset configuration to defaults - `edit` - Open config in editor ### Requirement: Config Path The config command SHALL display the config file location. #### Scenario: Show config path - **WHEN** user executes `openspec config path` - **THEN** print the absolute path to the config file - **AND** exit with code 0 ### Requirement: Config List The config command SHALL display all current configuration values. #### Scenario: List config in human-readable format - **WHEN** user executes `openspec config list` - **THEN** display all config values in YAML-like format - **AND** show nested objects with indentation #### Scenario: List config as JSON - **WHEN** user executes `openspec config list --json` - **THEN** output the complete config as valid JSON - **AND** output only JSON (no additional text) ### Requirement: Config Get The config command SHALL retrieve specific configuration values. #### Scenario: Get top-level key - **WHEN** user executes `openspec config get ` with a valid top-level key - **THEN** print the raw value only (no labels or formatting) - **AND** exit with code 0 #### Scenario: Get nested key with dot notation - **WHEN** user executes `openspec config get featureFlags.someFlag` - **THEN** traverse the nested structure using dot notation - **AND** print the value at that path #### Scenario: Get non-existent key - **WHEN** user executes `openspec config get ` with a key that does not exist - **THEN** print nothing (empty output) - **AND** exit with code 1 #### Scenario: Get object value - **WHEN** user executes `openspec config get ` where the value is an object - **THEN** print the object as JSON ### Requirement: Config Set The config command SHALL set configuration values with automatic type coercion. #### Scenario: Set string value - **WHEN** user executes `openspec config set ` - **AND** value does not match boolean or number patterns - **THEN** store value as a string - **AND** display confirmation message #### Scenario: Set boolean value - **WHEN** user executes `openspec config set true` or `openspec config set false` - **THEN** store value as boolean (not string) - **AND** display confirmation message #### Scenario: Set numeric value - **WHEN** user executes `openspec config set ` - **AND** value is a valid number (integer or float) - **THEN** store value as number (not string) #### Scenario: Force string with --string flag - **WHEN** user executes `openspec config set --string` - **THEN** store value as string regardless of content - **AND** this allows storing literal "true" or "123" as strings #### Scenario: Set nested key - **WHEN** user executes `openspec config set featureFlags.newFlag true` - **THEN** create intermediate objects if they don't exist - **AND** set the value at the nested path ### Requirement: Config Unset The config command SHALL remove configuration overrides. #### Scenario: Unset existing key - **WHEN** user executes `openspec config unset ` - **AND** the key exists in the config - **THEN** remove the key from the config file - **AND** the value reverts to its default - **AND** display confirmation message #### Scenario: Unset non-existent key - **WHEN** user executes `openspec config unset ` - **AND** the key does not exist in the config - **THEN** display message indicating key was not set - **AND** exit with code 0 ### Requirement: Config Reset The config command SHALL reset configuration to defaults. #### Scenario: Reset all with confirmation - **WHEN** user executes `openspec config reset --all` - **THEN** prompt for confirmation before proceeding - **AND** if confirmed, delete the config file or reset to defaults - **AND** display confirmation message #### Scenario: Reset all with -y flag - **WHEN** user executes `openspec config reset --all -y` - **THEN** reset without prompting for confirmation #### Scenario: Reset without --all flag - **WHEN** user executes `openspec config reset` without `--all` - **THEN** display error indicating `--all` is required - **AND** exit with code 1 ### Requirement: Config Edit The config command SHALL open the config file in the user's editor. #### Scenario: Open editor successfully - **WHEN** user executes `openspec config edit` - **AND** `$EDITOR` or `$VISUAL` environment variable is set - **THEN** open the config file in that editor - **AND** create the config file with defaults if it doesn't exist - **AND** wait for the editor to close before returning #### Scenario: No editor configured - **WHEN** user executes `openspec config edit` - **AND** neither `$EDITOR` nor `$VISUAL` is set - **THEN** display error message suggesting to set `$EDITOR` - **AND** exit with code 1 ### Requirement: Key Naming Convention The config command SHALL use camelCase keys matching the JSON structure. #### Scenario: Keys match JSON structure - **WHEN** accessing configuration keys via CLI - **THEN** use camelCase matching the actual JSON property names - **AND** support dot notation for nested access (e.g., `featureFlags.someFlag`) ### Requirement: Schema Validation The config command SHALL validate configuration writes against the config schema using zod, while allowing unknown fields for forward compatibility. #### Scenario: Unknown key accepted - **WHEN** user executes `openspec config set someFutureKey 123` - **THEN** the value is saved successfully - **AND** exit with code 0 #### Scenario: Invalid feature flag value rejected - **WHEN** user executes `openspec config set featureFlags.someFlag notABoolean` - **THEN** display a descriptive error message - **AND** do not modify the config file - **AND** exit with code 1 ### Requirement: Reserved Scope Flag The config command SHALL reserve the `--scope` flag for future extensibility. #### Scenario: Scope flag defaults to global - **WHEN** user executes any config command without `--scope` - **THEN** operate on global configuration (default behavior) #### Scenario: Project scope not yet implemented - **WHEN** user executes `openspec config --scope project ` - **THEN** display error message: "Project-local config is not yet implemented" - **AND** exit with code 1 ================================================ FILE: openspec/changes/archive/2025-12-21-add-config-command/tasks.md ================================================ ## 1. Core Infrastructure - [x] 1.1 Create zod schema for global config in `src/core/config-schema.ts` - [x] 1.2 Add utility functions for dot-notation key access (get/set nested values) - [x] 1.3 Add type coercion logic (auto-detect boolean/number/string) ## 2. Config Command Implementation - [x] 2.1 Create `src/commands/config.ts` with Commander.js subcommands - [x] 2.2 Implement `config path` subcommand - [x] 2.3 Implement `config list` subcommand with `--json` flag - [x] 2.4 Implement `config get ` subcommand (raw output) - [x] 2.5 Implement `config set ` with `--string` flag - [x] 2.6 Implement `config unset ` subcommand - [x] 2.7 Implement `config reset --all` with `-y` confirmation flag - [x] 2.8 Implement `config edit` subcommand (spawn $EDITOR) ## 3. Integration - [x] 3.1 Register config command in CLI entry point - [x] 3.2 Update shell completion registry to include config subcommands ## 4. Testing - [x] 4.1 Manual testing of all subcommands - [x] 4.2 Verify zod validation rejects invalid keys/values - [x] 4.3 Test nested key access with dot notation - [x] 4.4 Test type coercion edge cases (true/false, numbers, strings) ================================================ FILE: openspec/changes/archive/2025-12-23-extend-shell-completions/proposal.md ================================================ # Change Proposal: Extend Shell Completions ## Why Zsh completions provide an excellent developer experience, but many developers use bash, fish, or PowerShell. Extending completion support to these shells removes friction for the majority of developers who don't use Zsh. ## What Changes This change adds bash, fish, and PowerShell completion support following the same architectural patterns, documentation methodology, and testing rigor established for Zsh completions. ## Deltas - **Spec:** `cli-completion` - **Operation:** MODIFIED - **Description:** Extend completion generation, installation, and testing requirements to support bash, fish, and PowerShell while maintaining the existing Zsh implementation and architectural patterns ================================================ FILE: openspec/changes/archive/2025-12-23-extend-shell-completions/specs/cli-completion/spec.md ================================================ # cli-completion Spec Delta ## MODIFIED Requirements ### Requirement: Native Shell Behavior Integration The completion system SHALL respect and integrate with each supported shell's native completion patterns and user interaction model. #### Scenario: Zsh native completion - **WHEN** generating Zsh completion scripts - **THEN** use Zsh completion system with `_arguments`, `_describe`, and `compadd` - **AND** completions SHALL trigger on single TAB (standard Zsh behavior) - **AND** display as an interactive menu that users navigate with TAB/arrow keys - **AND** support Oh My Zsh's enhanced menu styling automatically #### Scenario: Bash native completion - **WHEN** generating Bash completion scripts - **THEN** use Bash completion with `complete` builtin and `COMPREPLY` array - **AND** completions SHALL trigger on double TAB (standard Bash behavior) - **AND** display as space-separated list or column format - **AND** support both bash-completion v1 and v2 patterns #### Scenario: Fish native completion - **WHEN** generating Fish completion scripts - **THEN** use Fish's `complete` command with conditions - **AND** completions SHALL trigger on single TAB with auto-suggestion preview - **AND** display with Fish's native coloring and description alignment - **AND** leverage Fish's built-in caching automatically #### Scenario: PowerShell native completion - **WHEN** generating PowerShell completion scripts - **THEN** use `Register-ArgumentCompleter` with scriptblock - **AND** completions SHALL trigger on TAB with cycling behavior - **AND** display with PowerShell's native completion UI - **AND** support both Windows PowerShell 5.1 and PowerShell Core 7+ #### Scenario: No custom UX patterns - **WHEN** implementing completion for any shell - **THEN** do NOT attempt to customize completion trigger behavior - **AND** do NOT override shell-specific navigation patterns - **AND** ensure completions feel native to experienced users of that shell ### Requirement: Shell Detection The completion system SHALL automatically detect the user's current shell environment. #### Scenario: Detecting Zsh from environment - **WHEN** no shell is explicitly specified - **THEN** read the `$SHELL` environment variable - **AND** extract the shell name from the path (e.g., `/bin/zsh` → `zsh`) - **AND** validate the shell is one of: `zsh`, `bash`, `fish`, `powershell` - **AND** throw an error if the shell is not supported #### Scenario: Detecting Bash from environment - **WHEN** `$SHELL` contains `bash` in the path - **THEN** detect shell as `bash` - **AND** proceed with bash-specific completion logic #### Scenario: Detecting Fish from environment - **WHEN** `$SHELL` contains `fish` in the path - **THEN** detect shell as `fish` - **AND** proceed with fish-specific completion logic #### Scenario: Detecting PowerShell from environment - **WHEN** `$PSModulePath` environment variable is present - **THEN** detect shell as `powershell` - **AND** proceed with PowerShell-specific completion logic #### Scenario: Unsupported shell detection - **WHEN** shell path indicates an unsupported shell - **THEN** throw error: "Shell '' is not supported. Supported shells: zsh, bash, fish, powershell" ### Requirement: Completion Generation The completion command SHALL generate completion scripts for all supported shells on demand. #### Scenario: Generating Zsh completion - **WHEN** user executes `openspec completion generate zsh` - **THEN** output a complete Zsh completion script to stdout - **AND** include completions for all commands: init, list, show, validate, archive, view, update, change, spec, completion - **AND** include all command-specific flags and options - **AND** use Zsh's `_arguments` and `_describe` built-in functions - **AND** support dynamic completion for change and spec IDs #### Scenario: Generating Bash completion - **WHEN** user executes `openspec completion generate bash` - **THEN** output a complete Bash completion script to stdout - **AND** include completions for all commands and subcommands - **AND** use `complete -F` with custom completion function - **AND** populate `COMPREPLY` with appropriate suggestions - **AND** support dynamic completion for change and spec IDs via `openspec __complete` #### Scenario: Generating Fish completion - **WHEN** user executes `openspec completion generate fish` - **THEN** output a complete Fish completion script to stdout - **AND** use `complete -c openspec` with conditions - **AND** include command-specific completions with `--condition` predicates - **AND** support dynamic completion for change and spec IDs via `openspec __complete` - **AND** include descriptions for each completion option #### Scenario: Generating PowerShell completion - **WHEN** user executes `openspec completion generate powershell` - **THEN** output a complete PowerShell completion script to stdout - **AND** use `Register-ArgumentCompleter -CommandName openspec` - **AND** implement scriptblock that handles command context - **AND** support dynamic completion for change and spec IDs via `openspec __complete` - **AND** return `[System.Management.Automation.CompletionResult]` objects ### Requirement: Installation Automation The completion command SHALL automatically install completion scripts into shell configuration files for all supported shells. #### Scenario: Installing for Oh My Zsh - **WHEN** user executes `openspec completion install zsh` - **THEN** detect if Oh My Zsh is installed by checking for `$ZSH` environment variable or `~/.oh-my-zsh/` directory - **AND** create custom completions directory at `~/.oh-my-zsh/custom/completions/` if it doesn't exist - **AND** write completion script to `~/.oh-my-zsh/custom/completions/_openspec` - **AND** ensure `~/.oh-my-zsh/custom/completions` is in `$fpath` by updating `~/.zshrc` if needed - **AND** display success message with instruction to run `exec zsh` or restart terminal #### Scenario: Installing for standard Zsh - **WHEN** user executes `openspec completion install zsh` and Oh My Zsh is not detected - **THEN** create completions directory at `~/.zsh/completions/` if it doesn't exist - **AND** write completion script to `~/.zsh/completions/_openspec` - **AND** add `fpath=(~/.zsh/completions $fpath)` to `~/.zshrc` if not already present - **AND** add `autoload -Uz compinit && compinit` to `~/.zshrc` if not already present - **AND** display success message with instruction to run `exec zsh` or restart terminal #### Scenario: Installing for Bash with bash-completion - **WHEN** user executes `openspec completion install bash` - **THEN** detect if bash-completion is installed by checking for `/usr/share/bash-completion` or `/etc/bash_completion.d` - **AND** if bash-completion is available, write to `/etc/bash_completion.d/openspec` (with sudo) or `~/.local/share/bash-completion/completions/openspec` - **AND** if bash-completion is not available, write to `~/.bash_completion.d/openspec` and source it from `~/.bashrc` - **AND** add sourcing line to `~/.bashrc` using marker-based updates if needed - **AND** display success message with instruction to run `exec bash` or restart terminal #### Scenario: Installing for Fish - **WHEN** user executes `openspec completion install fish` - **THEN** create Fish completions directory at `~/.config/fish/completions/` if it doesn't exist - **AND** write completion script to `~/.config/fish/completions/openspec.fish` - **AND** Fish automatically loads completions from this directory (no config file modification needed) - **AND** display success message indicating completions are immediately available #### Scenario: Installing for PowerShell - **WHEN** user executes `openspec completion install powershell` - **THEN** detect PowerShell profile location via `$PROFILE` environment variable or default paths - **AND** create profile directory if it doesn't exist - **AND** add completion script import to profile using marker-based updates - **AND** write completion script to PowerShell modules directory or alongside profile - **AND** display success message with instruction to restart PowerShell or run `. $PROFILE` #### Scenario: Auto-detecting shell for installation - **WHEN** user executes `openspec completion install` without specifying a shell - **THEN** detect current shell using shell detection logic - **AND** install completion for the detected shell (zsh, bash, fish, or powershell) - **AND** display which shell was detected #### Scenario: Already installed - **WHEN** completion is already installed for the target shell - **THEN** display message indicating completion is already installed - **AND** offer to reinstall/update by overwriting existing files - **AND** exit with code 0 ### Requirement: Uninstallation The completion command SHALL remove installed completion scripts and configuration for all supported shells. #### Scenario: Uninstalling Zsh completion - **WHEN** user executes `openspec completion uninstall zsh` - **THEN** prompt for confirmation before proceeding (unless `--yes` flag provided) - **AND** if user declines, cancel uninstall and display "Uninstall cancelled." - **AND** if user confirms, remove `~/.oh-my-zsh/custom/completions/_openspec` if Oh My Zsh is detected - **AND** remove `~/.zsh/completions/_openspec` if standard Zsh setup is detected - **AND** remove fpath modifications from `~/.zshrc` using marker-based removal - **AND** display success message #### Scenario: Uninstalling Bash completion - **WHEN** user executes `openspec completion uninstall bash` - **THEN** prompt for confirmation (unless `--yes` flag provided) - **AND** if user confirms, remove completion file from bash-completion directory or `~/.bash_completion.d/` - **AND** remove sourcing lines from `~/.bashrc` using marker-based removal - **AND** display success message #### Scenario: Uninstalling Fish completion - **WHEN** user executes `openspec completion uninstall fish` - **THEN** prompt for confirmation (unless `--yes` flag provided) - **AND** if user confirms, remove `~/.config/fish/completions/openspec.fish` - **AND** display success message (no config file modification needed) #### Scenario: Uninstalling PowerShell completion - **WHEN** user executes `openspec completion uninstall powershell` - **THEN** prompt for confirmation (unless `--yes` flag provided) - **AND** if user confirms, remove completion import from PowerShell profile using marker-based removal - **AND** remove completion script file - **AND** display success message #### Scenario: Auto-detecting shell for uninstallation - **WHEN** user executes `openspec completion uninstall` without specifying a shell - **THEN** detect current shell and uninstall completion for that shell #### Scenario: Not installed - **WHEN** attempting to uninstall completion that isn't installed - **THEN** display error message indicating completion is not installed - **AND** exit with code 1 ### Requirement: Architecture Patterns The completion implementation SHALL follow clean architecture principles with TypeScript best practices, supporting multiple shells through a plugin-based pattern. #### Scenario: Shell-specific generators - **WHEN** implementing completion generators - **THEN** create generator classes for each shell: `ZshGenerator`, `BashGenerator`, `FishGenerator`, `PowerShellGenerator` - **AND** implement a common `CompletionGenerator` interface with method: - `generate(commands: CommandDefinition[]): string` - Returns complete shell script - **AND** each generator handles shell-specific syntax, escaping, and patterns - **AND** all generators consume the same `CommandDefinition[]` from the command registry #### Scenario: Shell-specific installers - **WHEN** implementing completion installers - **THEN** create installer classes for each shell: `ZshInstaller`, `BashInstaller`, `FishInstaller`, `PowerShellInstaller` - **AND** implement a common `CompletionInstaller` interface with methods: - `install(script: string): Promise` - Installs completion script - `uninstall(): Promise<{ success: boolean; message: string }>` - Removes completion - **AND** each installer handles shell-specific paths, config files, and installation patterns #### Scenario: Factory pattern for shell selection - **WHEN** selecting shell-specific implementation - **THEN** use `CompletionFactory` class with static methods: - `createGenerator(shell: SupportedShell): CompletionGenerator` - `createInstaller(shell: SupportedShell): CompletionInstaller` - **AND** factory uses switch statements with TypeScript exhaustiveness checking - **AND** adding new shell requires updating `SupportedShell` type and factory cases #### Scenario: Dynamic completion providers - **WHEN** implementing dynamic completions - **THEN** create a `CompletionProvider` class that encapsulates project discovery logic - **AND** implement methods: - `getChangeIds(): Promise` - Discovers active change IDs - `getSpecIds(): Promise` - Discovers spec IDs - `isOpenSpecProject(): boolean` - Checks if current directory is OpenSpec-enabled - **AND** implement caching with 2-second TTL using class properties #### Scenario: Command registry - **WHEN** defining completable commands - **THEN** create a centralized `CommandDefinition` type with properties: - `name: string` - Command name - `description: string` - Help text - `flags: FlagDefinition[]` - Available flags - `acceptsPositional: boolean` - Whether command takes positional arguments - `positionalType: string` - Type of positional (change-id, spec-id, path, shell) - `subcommands?: CommandDefinition[]` - Nested subcommands - **AND** export a `COMMAND_REGISTRY` constant with all command definitions - **AND** all generators consume this registry to ensure consistency across shells #### Scenario: Type-safe shell detection - **WHEN** implementing shell detection - **THEN** define a `SupportedShell` type as literal type: `'zsh' | 'bash' | 'fish' | 'powershell'` - **AND** implement `detectShell()` function in `src/utils/shell-detection.ts` - **AND** return detected shell or throw error with supported shells list ### Requirement: Testing Support The completion implementation SHALL be testable with unit and integration tests for all supported shells. #### Scenario: Mock shell environment - **WHEN** writing tests for shell detection - **THEN** allow overriding `$SHELL` and `$PSModulePath` environment variables - **AND** use dependency injection for file system operations - **AND** test detection for all four shells independently #### Scenario: Generator output verification - **WHEN** testing completion generators - **THEN** create test suite for each shell generator (zsh, bash, fish, powershell) - **AND** verify generated scripts contain expected patterns for that shell - **AND** test that command registry is properly consumed - **AND** ensure dynamic completion placeholders are present - **AND** verify shell-specific syntax and escaping #### Scenario: Installer simulation - **WHEN** testing installation logic - **THEN** create test suite for each shell installer - **AND** use temporary test directories instead of actual home directories - **AND** verify file creation without modifying real shell configurations - **AND** test path resolution logic independently - **AND** mock file system operations to avoid side effects #### Scenario: Cross-shell consistency - **WHEN** testing completion behavior - **THEN** verify all shells support the same commands and flags - **AND** verify dynamic completions work consistently across shells - **AND** ensure error messages are consistent across shells ================================================ FILE: openspec/changes/archive/2025-12-23-extend-shell-completions/tasks.md ================================================ # Implementation Tasks ## Phase 1: Foundation and Bash Support - [x] Update `SupportedShell` type in `src/utils/shell-detection.ts` to include `'bash' | 'fish' | 'powershell'` - [x] Extend shell detection logic to recognize bash, fish, and PowerShell from environment variables - [x] Create `src/core/completions/generators/bash-generator.ts` implementing `CompletionGenerator` interface - [x] Create `src/core/completions/installers/bash-installer.ts` implementing `CompletionInstaller` interface - [x] Update `CompletionFactory.createGenerator()` to support bash - [x] Update `CompletionFactory.createInstaller()` to support bash - [x] Create test file `test/core/completions/generators/bash-generator.test.ts` mirroring zsh test structure - [x] Create test file `test/core/completions/installers/bash-installer.test.ts` mirroring zsh test structure - [x] Verify bash completions work manually: `openspec completion install bash && exec bash` ## Phase 2: Fish Support - [x] Create `src/core/completions/generators/fish-generator.ts` implementing `CompletionGenerator` interface - [x] Create `src/core/completions/installers/fish-installer.ts` implementing `CompletionInstaller` interface - [x] Update `CompletionFactory.createGenerator()` to support fish - [x] Update `CompletionFactory.createInstaller()` to support fish - [x] Create test file `test/core/completions/generators/fish-generator.test.ts` - [x] Create test file `test/core/completions/installers/fish-installer.test.ts` - [x] Verify fish completions work manually: `openspec completion install fish` ## Phase 3: PowerShell Support - [x] Create `src/core/completions/generators/powershell-generator.ts` implementing `CompletionGenerator` interface - [x] Create `src/core/completions/installers/powershell-installer.ts` implementing `CompletionInstaller` interface - [x] Update `CompletionFactory.createGenerator()` to support powershell - [x] Update `CompletionFactory.createInstaller()` to support powershell - [x] Create test file `test/core/completions/generators/powershell-generator.test.ts` - [x] Create test file `test/core/completions/installers/powershell-installer.test.ts` - [x] Verify PowerShell completions work manually on Windows or macOS PowerShell ## Phase 4: Documentation and Testing - [x] Update `CLAUDE.md` or relevant documentation to mention all four supported shells - [x] Add cross-shell consistency test verifying all shells support same commands - [x] Run `pnpm test` to ensure all tests pass - [x] Run `pnpm run build` to verify TypeScript compilation - [x] Test all shells on different platforms (Linux for bash/fish/zsh, Windows/macOS for PowerShell) ## Phase 5: Validation and Cleanup - [x] Run `openspec validate extend-shell-completions --strict` and resolve all issues - [x] Update error messages to list all four supported shells - [x] Verify `openspec completion --help` documentation is current - [x] Test auto-detection works for all shells - [x] Ensure uninstall works cleanly for all shells ================================================ FILE: openspec/changes/archive/2025-12-24-add-artifact-graph-core/design.md ================================================ ## Context This implements "Slice 1: What's Ready?" from the artifact POC analysis. The core insight is using the filesystem as a database - artifact completion is detected by file existence, making the system stateless and version-control friendly. This module will coexist with the current OpenSpec system as a parallel capability, potentially enabling future migration or integration. ## Goals / Non-Goals **Goals:** - Pure dependency graph logic with no side effects - Stateless state detection (rescan filesystem each query) - Support glob patterns for multi-file artifacts (e.g., `specs/*.md`) - Load artifact definitions from YAML schemas - Calculate topological build order - Determine "ready" artifacts based on dependency completion **Non-Goals:** - CLI commands (Slice 4) - Multi-change management (Slice 2) - Template resolution and enrichment (Slice 3) - Agent integration or Claude commands - Replacing existing OpenSpec functionality ## Decisions ### Decision: Filesystem as Database Use file existence for state detection rather than a separate state file. **Rationale:** - Stateless - no state corruption possible - Git-friendly - state derived from committed files - Simple - no sync issues between state file and actual files **Alternatives considered:** - JSON/SQLite state file: More complex, sync issues, not git-friendly - Git metadata: Too coupled to git, complex implementation ### Decision: Kahn's Algorithm for Topological Sort Use Kahn's algorithm for computing build order. **Rationale:** - Well-understood, O(V+E) complexity - Naturally detects cycles during execution - Produces a stable, deterministic order ### Decision: Glob Pattern Support Support glob patterns like `specs/*.md` in artifact `generates` field. **Rationale:** - Allows multiple files to satisfy a single artifact requirement - Common pattern for spec directories with multiple files - Uses standard glob syntax ### Decision: Immutable Completed Set Represent completion state as an immutable Set of completed artifact IDs. **Rationale:** - Functional style, easier to reason about - State derived fresh each query, no mutation needed - Clear separation between graph structure and runtime state - Filesystem can only detect binary existence (complete vs not complete) **Note:** `inProgress` and `failed` states are deferred to future slices. They would require external state tracking (e.g., a status file) since file existence alone cannot distinguish these states. ### Decision: Zod for Schema Validation Use Zod for validating YAML schema structure and deriving TypeScript types. **Rationale:** - Already a project dependency (v4.0.17) used in `src/core/schemas/` - Type inference via `z.infer<>` - single source of truth for types - Runtime validation with detailed error messages - Consistent with existing project patterns (`base.schema.ts`, `config-schema.ts`) **Alternatives considered:** - Manual validation: More code, error-prone, no type inference - JSON Schema: Would require additional dependency, less TypeScript integration - io-ts: Not already in project, steeper learning curve ### Decision: Two-Level Schema Resolution Schemas resolve from global user data directory, falling back to package built-ins. **Resolution order:** 1. `${XDG_DATA_HOME:-~/.local/share}/openspec/schemas/.yaml` - Global user override 2. `/schemas/.yaml` - Built-in defaults **Rationale:** - Follows XDG Base Directory Specification (schemas are data, not config) - Mirrors existing `getGlobalConfigDir()` pattern in `src/core/global-paths.ts` - Built-ins baked into package, never auto-copied - Users customize by creating files in global data dir - Simple - no project-level overrides (can add later if needed) **XDG compliance:** - Uses `XDG_DATA_HOME` env var when set (all platforms) - Unix/macOS fallback: `~/.local/share/openspec/` - Windows fallback: `%LOCALAPPDATA%/openspec/` **Alternatives considered:** - Project-level overrides: Added complexity, not needed initially - Auto-copy to user space: Creates drift, harder to update defaults - Config directory (`XDG_CONFIG_HOME`): Schemas are workflow definitions (data), not user preferences (config) ### Decision: Template Field Parsed But Not Resolved The `template` field is required in schema YAML for completeness, but template resolution is deferred to Slice 3. **Rationale:** - Slice 1 focuses on "What's Ready?" - dependency and completion queries only - Template paths are validated syntactically (non-empty string) but not resolved - Keeps Slice 1 focused and independently testable ### Decision: Cycle Error Format Cycle errors list all artifact IDs in the cycle for easy debugging. **Format:** `"Cyclic dependency detected: A → B → C → A"` **Rationale:** - Shows the full cycle path, not just that a cycle exists - Actionable - developer can see exactly which artifacts to fix - Consistent with Kahn's algorithm which naturally identifies cycle participants ## Data Structures **Zod Schemas (source of truth):** ```typescript import { z } from 'zod'; // Artifact definition schema export const ArtifactSchema = z.object({ id: z.string().min(1, 'Artifact ID is required'), generates: z.string().min(1), // e.g., "proposal.md" or "specs/*.md" description: z.string(), template: z.string(), // path to template file requires: z.array(z.string()).default([]), }); // Full schema YAML structure export const SchemaYamlSchema = z.object({ name: z.string().min(1, 'Schema name is required'), version: z.number().int().positive(), description: z.string().optional(), artifacts: z.array(ArtifactSchema).min(1, 'At least one artifact required'), }); // Derived TypeScript types export type Artifact = z.infer; export type SchemaYaml = z.infer; ``` **Runtime State (not Zod - internal only):** ```typescript // Slice 1: Simple completion tracking via filesystem type CompletedSet = Set; // Return type for blocked query interface BlockedArtifacts { [artifactId: string]: string[]; // artifact → list of unmet dependencies } interface ArtifactGraphResult { completed: string[]; ready: string[]; blocked: BlockedArtifacts; buildOrder: string[]; } ``` ## File Structure ``` src/core/artifact-graph/ ├── index.ts # Public exports ├── types.ts # Zod schemas and type definitions ├── graph.ts # ArtifactGraph class ├── state.ts # State detection logic ├── resolver.ts # Schema resolution (global → built-in) └── schemas/ # Built-in schema definitions (package level) ├── spec-driven.yaml # Default: proposal → specs → design → tasks └── tdd.yaml # Alternative: tests → implementation → docs ``` **Schema Resolution Paths:** - Global user override: `${XDG_DATA_HOME:-~/.local/share}/openspec/schemas/.yaml` - Package built-in: `src/core/artifact-graph/schemas/.yaml` (bundled with package) ## Risks / Trade-offs | Risk | Mitigation | |------|------------| | Glob pattern edge cases | Use well-tested glob library (fast-glob or similar) | | Cycle detection | Kahn's algorithm naturally fails on cycles; provide clear error | | Schema evolution | Version field in schema, validate on load | ## Open Questions None - all questions resolved in Decisions section. ================================================ FILE: openspec/changes/archive/2025-12-24-add-artifact-graph-core/proposal.md ================================================ ## Why The current OpenSpec system relies on conventions and AI inference for artifact ordering. A formal artifact graph with dependency awareness would enable deterministic "what's ready?" queries, making the system more predictable and enabling future features like automated pipeline execution. ## What Changes - Add `ArtifactGraph` class to model artifacts as a DAG with dependency relationships - Add `ArtifactState` type to track completion status (completed, in_progress, failed) - Add filesystem-based state detection using file existence and glob patterns - Add schema YAML parser to load artifact definitions - Implement topological sort (Kahn's algorithm) for build order calculation - Add `getNextArtifacts()` to find artifacts ready for creation ## Impact - Affected specs: New `artifact-graph` capability - Affected code: `src/core/artifact-graph/` (new directory) - No changes to existing functionality - this is a parallel module ================================================ FILE: openspec/changes/archive/2025-12-24-add-artifact-graph-core/specs/artifact-graph/spec.md ================================================ ## ADDED Requirements ### Requirement: Schema Loading The system SHALL load artifact graph definitions from YAML schema files. #### Scenario: Valid schema loaded - **WHEN** a valid schema YAML file is provided - **THEN** the system returns an ArtifactGraph with all artifacts and dependencies #### Scenario: Invalid schema rejected - **WHEN** a schema YAML file is missing required fields - **THEN** the system throws an error with a descriptive message #### Scenario: Cyclic dependencies detected - **WHEN** a schema contains cyclic artifact dependencies - **THEN** the system throws an error listing the artifact IDs in the cycle #### Scenario: Invalid dependency reference - **WHEN** an artifact's `requires` array references a non-existent artifact ID - **THEN** the system throws an error identifying the invalid reference #### Scenario: Duplicate artifact IDs rejected - **WHEN** a schema contains multiple artifacts with the same ID - **THEN** the system throws an error identifying the duplicate ### Requirement: Build Order Calculation The system SHALL compute a valid topological build order for artifacts. #### Scenario: Linear dependency chain - **WHEN** artifacts form a linear chain (A → B → C) - **THEN** getBuildOrder() returns [A, B, C] #### Scenario: Diamond dependency - **WHEN** artifacts form a diamond (A → B, A → C, B → D, C → D) - **THEN** getBuildOrder() returns A before B and C, and D last #### Scenario: Independent artifacts - **WHEN** artifacts have no dependencies - **THEN** getBuildOrder() returns them in a stable order ### Requirement: State Detection The system SHALL detect artifact completion state by scanning the filesystem. #### Scenario: Simple file exists - **WHEN** an artifact generates "proposal.md" and the file exists - **THEN** the artifact is marked as completed #### Scenario: Simple file missing - **WHEN** an artifact generates "proposal.md" and the file does not exist - **THEN** the artifact is not marked as completed #### Scenario: Glob pattern with files - **WHEN** an artifact generates "specs/*.md" and the specs/ directory contains .md files - **THEN** the artifact is marked as completed #### Scenario: Glob pattern empty - **WHEN** an artifact generates "specs/*.md" and the specs/ directory is empty or missing - **THEN** the artifact is not marked as completed #### Scenario: Missing change directory - **WHEN** the change directory does not exist - **THEN** all artifacts are marked as not completed (empty state) ### Requirement: Ready Artifact Query The system SHALL identify which artifacts are ready to be created based on dependency completion. #### Scenario: Root artifacts ready initially - **WHEN** no artifacts are completed - **THEN** getNextArtifacts() returns artifacts with no dependencies #### Scenario: Dependent artifact becomes ready - **WHEN** an artifact's dependencies are all completed - **THEN** getNextArtifacts() includes that artifact #### Scenario: Blocked artifacts excluded - **WHEN** an artifact has uncompleted dependencies - **THEN** getNextArtifacts() does not include that artifact ### Requirement: Completion Check The system SHALL determine when all artifacts in a graph are complete. #### Scenario: All complete - **WHEN** all artifacts in the graph are in the completed set - **THEN** isComplete() returns true #### Scenario: Partially complete - **WHEN** some artifacts in the graph are not completed - **THEN** isComplete() returns false ### Requirement: Blocked Query The system SHALL identify which artifacts are blocked and return all their unmet dependencies. #### Scenario: Artifact blocked by single dependency - **WHEN** artifact B requires artifact A and A is not complete - **THEN** getBlocked() returns `{ B: ['A'] }` #### Scenario: Artifact blocked by multiple dependencies - **WHEN** artifact C requires A and B, and only A is complete - **THEN** getBlocked() returns `{ C: ['B'] }` #### Scenario: Artifact blocked by all dependencies - **WHEN** artifact C requires A and B, and neither is complete - **THEN** getBlocked() returns `{ C: ['A', 'B'] }` ================================================ FILE: openspec/changes/archive/2025-12-24-add-artifact-graph-core/tasks.md ================================================ ## 1. Type Definitions - [x] 1.1 Create `src/core/artifact-graph/types.ts` with Zod schemas (`ArtifactSchema`, `SchemaYamlSchema`) and inferred types via `z.infer<>` - [x] 1.2 Define `CompletedSet` (Set), `BlockedArtifacts`, and `ArtifactGraphResult` types for runtime state ## 2. Schema Parser - [x] 2.1 Create `src/core/artifact-graph/schema.ts` with YAML loading and Zod validation via `.safeParse()` - [x] 2.2 Implement dependency reference validation (ensure `requires` references valid artifact IDs) - [x] 2.3 Implement duplicate artifact ID detection - [x] 2.4 Add cycle detection during schema load (error format: "Cyclic dependency detected: A → B → C → A") ## 3. Artifact Graph Core - [x] 3.1 Create `src/core/artifact-graph/graph.ts` with ArtifactGraph class - [x] 3.2 Implement `fromYaml(path)` - load graph from schema file - [x] 3.3 Implement `getBuildOrder()` - topological sort via Kahn's algorithm - [x] 3.4 Implement `getArtifact(id)` - retrieve single artifact definition - [x] 3.5 Implement `getAllArtifacts()` - list all artifacts ## 4. State Detection - [x] 4.1 Create `src/core/artifact-graph/state.ts` with state detection logic - [x] 4.2 Implement file existence checking for simple paths - [x] 4.3 Implement glob pattern matching for multi-file artifacts - [x] 4.4 Implement `detectCompleted(graph, changeDir)` - scan filesystem and return CompletedSet - [x] 4.5 Handle missing changeDir gracefully (return empty CompletedSet) ## 5. Ready Calculation - [x] 5.1 Implement `getNextArtifacts(graph, completed)` - find artifacts with all deps completed - [x] 5.2 Implement `isComplete(graph, completed)` - check if all artifacts done - [x] 5.3 Implement `getBlocked(graph, completed)` - return BlockedArtifacts map (artifact → unmet deps) ## 6. Schema Resolution - [x] 6.1 Create `src/core/artifact-graph/resolver.ts` with schema resolution logic - [x] 6.2 Add `getGlobalDataDir()` to `src/core/global-config.ts` (XDG_DATA_HOME with platform fallbacks) - [x] 6.3 Implement `resolveSchema(name)` - global (`${XDG_DATA_HOME}/openspec/schemas/`) → built-in fallback ## 7. Built-in Schemas - [x] 7.1 Create `src/core/artifact-graph/schemas/spec-driven.yaml` (default: proposal → specs → design → tasks) - [x] 7.2 Create `src/core/artifact-graph/schemas/tdd.yaml` (alternative: tests → implementation → docs) ## 8. Integration - [x] 8.1 Create `src/core/artifact-graph/index.ts` with public exports ## 9. Testing - [x] 9.1 Test: Parse valid schema YAML returns correct artifact graph - [x] 9.2 Test: Parse invalid schema (missing fields) throws descriptive error - [x] 9.3 Test: Duplicate artifact IDs throws error - [x] 9.4 Test: Invalid `requires` reference throws error identifying the invalid ID - [x] 9.5 Test: Cycle in schema throws error listing cycle path (e.g., "A → B → C → A") - [x] 9.6 Test: Compute build order returns correct topological ordering (linear chain) - [x] 9.7 Test: Compute build order handles diamond dependencies correctly - [x] 9.8 Test: Independent artifacts return in stable order - [x] 9.9 Test: Empty/missing changeDir returns empty CompletedSet - [x] 9.10 Test: File existence marks artifact as completed - [x] 9.11 Test: Glob pattern specs/*.md detected as complete when files exist - [x] 9.12 Test: Glob pattern with empty directory not marked complete - [x] 9.13 Test: getNextArtifacts returns only root artifacts when nothing completed - [x] 9.14 Test: getNextArtifacts includes artifact when all deps completed - [x] 9.15 Test: getBlocked returns artifact with all unmet dependencies listed - [x] 9.16 Test: isComplete() returns true when all artifacts completed - [x] 9.17 Test: isComplete() returns false when some artifacts incomplete - [x] 9.18 Test: Schema resolution finds global override before built-in - [x] 9.19 Test: Schema resolution falls back to built-in when no global ================================================ FILE: openspec/changes/archive/2025-12-25-add-change-manager/design.md ================================================ ## Context This is Slice 2 of the artifact tracker POC. The goal is to provide utilities for creating change directories programmatically. **Current state:** No programmatic way to create changes. Users must manually create directories. **Proposed state:** Utility functions for change creation with name validation. ## Goals / Non-Goals ### Goals - **Add** `createChange()` function to create change directories - **Add** `validateChangeName()` function for kebab-case validation - **Enable** automation (Claude commands, scripts) to create changes ### Non-Goals - Refactor existing CLI commands (they work fine) - Create abstraction layers or manager classes - Change how `ListCommand` or `ChangeCommand` work ## Decisions ### Decision 1: Simple Utility Functions **Choice**: Add functions to `src/utils/change-utils.ts` - no class. ```typescript // src/utils/change-utils.ts export function validateChangeName(name: string): { valid: boolean; error?: string } export async function createChange( projectRoot: string, name: string ): Promise ``` **Why**: - Simple, no abstraction overhead - Easy to test - Easy to import where needed - Matches existing utility patterns in `src/utils/` **Alternatives considered**: - ChangeManager class: Rejected - over-engineered for 2 functions - Add to existing command: Rejected - mixes CLI with reusable logic ### Decision 2: Kebab-Case Validation Pattern **Choice**: Validate names with `^[a-z][a-z0-9]*(-[a-z0-9]+)*$` Valid: `add-auth`, `refactor-db`, `add-feature-2`, `refactor` Invalid: `Add-Auth`, `add auth`, `add_auth`, `-add-auth`, `add-auth-`, `add--auth` **Why**: - Filesystem-safe (no special characters) - URL-safe (for future web UI) - Consistent with existing change naming in repo ## File Changes ### New Files - `src/utils/change-utils.ts` - Utility functions - `src/utils/change-utils.test.ts` - Unit tests ### Modified Files - None ## Risks / Trade-offs | Risk | Mitigation | |------|------------| | Function might not cover all use cases | Start simple, extend if needed | | Naming conflicts with future work | Using clear, specific function names | ================================================ FILE: openspec/changes/archive/2025-12-25-add-change-manager/proposal.md ================================================ ## Why There's no programmatic way to create a new change directory. Users must manually: 1. Create `openspec/changes//` directory 2. Create a `proposal.md` file 3. Hope they got the naming right This is error-prone and blocks automation (e.g., Claude commands, scripts). **This proposal adds:** 1. `createChange(projectRoot, name)` - Create change directories programmatically 2. `validateChangeName(name)` - Enforce kebab-case naming conventions ## What Changes ### New Utilities | Function | Description | |----------|-------------| | `createChange(projectRoot, name)` | Creates `openspec/changes//` directory | | `validateChangeName(name)` | Returns `{ valid: boolean; error?: string }` | ### Name Validation Rules Pattern: `^[a-z][a-z0-9]*(-[a-z0-9]+)*$` | Valid | Invalid | |-------|---------| | `add-auth` | `Add-Auth` (uppercase) | | `refactor-db` | `add auth` (spaces) | | `add-feature-2` | `add_auth` (underscores) | | `refactor` | `-add-auth` (leading hyphen) | ### Location New file: `src/utils/change-utils.ts` Simple utility functions - no class, no abstraction layer. ## Impact - **Affected specs**: None - **Affected code**: None (new utilities only) - **New files**: `src/utils/change-utils.ts` - **Breaking changes**: None ================================================ FILE: openspec/changes/archive/2025-12-25-add-change-manager/specs/change-creation/spec.md ================================================ ## ADDED Requirements ### Requirement: Change Creation The system SHALL provide a function to create new change directories programmatically. #### Scenario: Create change - **WHEN** `createChange(projectRoot, 'add-auth')` is called - **THEN** the system creates `openspec/changes/add-auth/` directory #### Scenario: Duplicate change rejected - **WHEN** `createChange(projectRoot, 'add-auth')` is called and `openspec/changes/add-auth/` already exists - **THEN** the system throws an error indicating the change already exists #### Scenario: Creates parent directories if needed - **WHEN** `createChange(projectRoot, 'add-auth')` is called and `openspec/changes/` does not exist - **THEN** the system creates the full path including parent directories #### Scenario: Invalid change name rejected - **WHEN** `createChange(projectRoot, 'Add Auth')` is called with an invalid name - **THEN** the system throws a validation error ### Requirement: Change Name Validation The system SHALL validate change names follow kebab-case conventions. #### Scenario: Valid kebab-case name accepted - **WHEN** a change name like `add-user-auth` is validated - **THEN** validation returns `{ valid: true }` #### Scenario: Numeric suffixes accepted - **WHEN** a change name like `add-feature-2` is validated - **THEN** validation returns `{ valid: true }` #### Scenario: Single word accepted - **WHEN** a change name like `refactor` is validated - **THEN** validation returns `{ valid: true }` #### Scenario: Uppercase characters rejected - **WHEN** a change name like `Add-Auth` is validated - **THEN** validation returns `{ valid: false, error: "..." }` #### Scenario: Spaces rejected - **WHEN** a change name like `add auth` is validated - **THEN** validation returns `{ valid: false, error: "..." }` #### Scenario: Underscores rejected - **WHEN** a change name like `add_auth` is validated - **THEN** validation returns `{ valid: false, error: "..." }` #### Scenario: Special characters rejected - **WHEN** a change name like `add-auth!` is validated - **THEN** validation returns `{ valid: false, error: "..." }` #### Scenario: Leading hyphen rejected - **WHEN** a change name like `-add-auth` is validated - **THEN** validation returns `{ valid: false, error: "..." }` #### Scenario: Trailing hyphen rejected - **WHEN** a change name like `add-auth-` is validated - **THEN** validation returns `{ valid: false, error: "..." }` #### Scenario: Consecutive hyphens rejected - **WHEN** a change name like `add--auth` is validated - **THEN** validation returns `{ valid: false, error: "..." }` ================================================ FILE: openspec/changes/archive/2025-12-25-add-change-manager/tasks.md ================================================ ## Phase 1: Implement Name Validation - [x] 1.1 Create `src/utils/change-utils.ts` - [x] 1.2 Implement `validateChangeName()` with kebab-case pattern - [x] 1.3 Pattern: `^[a-z][a-z0-9]*(-[a-z0-9]+)*$` - [x] 1.4 Return `{ valid: boolean; error?: string }` - [x] 1.5 Add test: valid names accepted (`add-auth`, `refactor`, `add-feature-2`) - [x] 1.6 Add test: uppercase rejected - [x] 1.7 Add test: spaces rejected - [x] 1.8 Add test: underscores rejected - [x] 1.9 Add test: special characters rejected - [x] 1.10 Add test: leading/trailing hyphens rejected - [x] 1.11 Add test: consecutive hyphens rejected ## Phase 2: Implement Change Creation - [x] 2.1 Implement `createChange(projectRoot, name)` - [x] 2.2 Validate name before creating - [x] 2.3 Create parent directories if needed (`openspec/changes/`) - [x] 2.4 Throw if change already exists - [x] 2.5 Add test: creates directory - [x] 2.6 Add test: duplicate change throws error - [x] 2.7 Add test: invalid name throws validation error - [x] 2.8 Add test: creates parent directories if needed ## Phase 3: Integration - [x] 3.1 Export functions from `src/utils/index.ts` - [x] 3.2 Add JSDoc comments - [x] 3.3 Run all tests to verify no regressions ================================================ FILE: openspec/changes/archive/2025-12-28-add-artifact-workflow-cli/design.md ================================================ ## Context Slice 4 of the artifact workflow POC. The core functionality (ArtifactGraph, InstructionLoader, change-utils) is complete. This slice adds CLI commands to expose the artifact workflow to users. **Key constraint**: This is experimental. Commands must be isolated for easy removal if the feature doesn't work out. ## Goals / Non-Goals - **Goals:** - Expose artifact workflow status and instructions via CLI - Provide fluid UX with top-level verb commands - Support both human-readable and JSON output - Enable agents to programmatically query workflow state - Keep implementation isolated for easy removal - **Non-Goals:** - Interactive artifact creation wizards (future work) - Schema management commands (deferred) - Auto-detection of active change (CLI is deterministic, agents infer) ## Decisions ### Command Structure: Top-Level Verbs Commands are top-level for maximum fluidity: ``` openspec status --change openspec next --change openspec instructions --change openspec templates [--schema ] openspec new change ``` **Rationale:** - Most fluid UX - fewest keystrokes - Commands are unique enough to avoid conflicts - Simple mental model for users **Trade-off accepted:** Slight namespace pollution, but commands are distinct and can be removed cleanly. ### Experimental Isolation All artifact workflow commands are implemented in a single file: ``` src/commands/artifact-workflow.ts ``` **To remove the feature:** 1. Delete `src/commands/artifact-workflow.ts` 2. Remove ~5 lines from `src/cli/index.ts` No other files touched, no risk to stable functionality. ### Deterministic CLI with Explicit `--change` All change-specific commands require `--change `: ```bash openspec status --change add-auth # explicit, works openspec status # error: missing --change ``` **Rationale:** - CLI is pure, testable, no hidden state - Agents infer change from conversation and pass explicitly - No config file tracking "active change" - Consistent with POC design philosophy ### New Change Command Structure Creating changes uses explicit subcommand: ```bash openspec new change add-feature ``` **Rationale:** - `openspec new ` is ambiguous (new what?) - `openspec new change ` is clear and extensible - Can add `openspec new spec ` later if needed ### Output Formats - **Default**: Human-readable text with visual indicators - Status: `[x]` done, `[ ]` ready, `[-]` blocked - Colors: green (done), yellow (ready), red (blocked) - **JSON** (`--json`): Machine-readable for scripts and agents ### Error Handling - Missing `--change`: Error listing available changes - Unknown change: Error with suggestion - Unknown artifact: Error listing valid artifacts - Missing schema: Error with schema resolution details ## Risks / Trade-offs | Risk | Mitigation | |------|------------| | Top-level commands pollute namespace | Commands are distinct; isolated for easy removal | | `status` confused with git | Context (`--change`) makes it clear | | Feature doesn't work out | Single file deletion removes everything | ## Implementation Notes - All commands in `src/commands/artifact-workflow.ts` - Imports from `src/core/artifact-graph/` for all operations - Uses `getActiveChangeIds()` from `item-discovery.ts` for change listing - Follows existing CLI patterns (ora spinners, commander.js options) - Help text marks commands as "Experimental" ================================================ FILE: openspec/changes/archive/2025-12-28-add-artifact-workflow-cli/proposal.md ================================================ ## Why The ArtifactGraph (Slice 1) and InstructionLoader (Slice 3) provide programmatic APIs for artifact-based workflow management. Users currently have no CLI interface to: - See artifact completion status for a change - Discover what artifacts are ready to create - Get enriched instructions for creating artifacts - Create new changes with proper validation This proposal adds CLI commands that expose the artifact workflow functionality to users and agents. ## What Changes - **NEW**: `openspec status --change ` shows artifact completion state - **NEW**: `openspec next --change ` shows artifacts ready to create - **NEW**: `openspec instructions --change ` outputs enriched template - **NEW**: `openspec templates [--schema ]` shows resolved template paths - **NEW**: `openspec new change ` creates a new change directory All commands are top-level for fluid UX. They integrate with existing core modules: - Uses `loadChangeContext()`, `formatChangeStatus()`, `generateInstructions()` from instruction-loader - Uses `ArtifactGraph`, `detectCompleted()` from artifact-graph - Uses `createChange()`, `validateChangeName()` from change-utils **Experimental isolation**: All commands are implemented in a single file (`src/commands/artifact-workflow.ts`) for easy removal if the feature doesn't work out. Help text marks them as experimental. ## Impact - Affected specs: NEW `cli-artifact-workflow` capability - Affected code: - `src/cli/index.ts` - register new commands - `src/commands/artifact-workflow.ts` - new command implementations - No changes to existing commands or specs - Builds on completed Slice 1, 2, and 3 implementations ================================================ FILE: openspec/changes/archive/2025-12-28-add-artifact-workflow-cli/specs/cli-artifact-workflow/spec.md ================================================ # cli-artifact-workflow Specification ## Purpose CLI commands for artifact workflow operations, exposing the artifact graph and instruction loader functionality to users and agents. Commands are top-level for fluid UX and implemented in isolation for easy removal. ## ADDED Requirements ### Requirement: Status Command The system SHALL display artifact completion status for a change. #### Scenario: Show status with all states - **WHEN** user runs `openspec status --change ` - **THEN** the system displays each artifact with status indicator: - `[x]` for completed artifacts - `[ ]` for ready artifacts - `[-]` for blocked artifacts (with missing dependencies listed) #### Scenario: Status shows completion summary - **WHEN** user runs `openspec status --change ` - **THEN** output includes completion percentage and count (e.g., "2/4 artifacts complete") #### Scenario: Status JSON output - **WHEN** user runs `openspec status --change --json` - **THEN** the system outputs JSON with changeName, schemaName, isComplete, and artifacts array #### Scenario: Missing change parameter - **WHEN** user runs `openspec status` without `--change` - **THEN** the system displays an error with list of available changes #### Scenario: Unknown change - **WHEN** user runs `openspec status --change unknown-id` - **THEN** the system displays an error indicating the change does not exist ### Requirement: Next Command The system SHALL show which artifacts are ready to be created. #### Scenario: Show ready artifacts - **WHEN** user runs `openspec next --change ` - **THEN** the system lists artifacts whose dependencies are all satisfied #### Scenario: No artifacts ready - **WHEN** all artifacts are either completed or blocked - **THEN** the system indicates no artifacts are ready (with explanation) #### Scenario: All artifacts complete - **WHEN** all artifacts in the change are completed - **THEN** the system indicates the change is complete #### Scenario: Next JSON output - **WHEN** user runs `openspec next --change --json` - **THEN** the system outputs JSON array of ready artifact IDs ### Requirement: Instructions Command The system SHALL output enriched instructions for creating an artifact. #### Scenario: Show enriched instructions - **WHEN** user runs `openspec instructions --change ` - **THEN** the system outputs: - Artifact metadata (ID, output path, description) - Template content - Dependency status (done/missing) - Unlocked artifacts (what becomes available after completion) #### Scenario: Instructions JSON output - **WHEN** user runs `openspec instructions --change --json` - **THEN** the system outputs JSON matching ArtifactInstructions interface #### Scenario: Unknown artifact - **WHEN** user runs `openspec instructions unknown-artifact --change ` - **THEN** the system displays an error listing valid artifact IDs for the schema #### Scenario: Artifact with unmet dependencies - **WHEN** user requests instructions for a blocked artifact - **THEN** the system displays instructions with a warning about missing dependencies ### Requirement: Templates Command The system SHALL show resolved template paths for all artifacts in a schema. #### Scenario: List template paths with default schema - **WHEN** user runs `openspec templates` - **THEN** the system displays each artifact with its resolved template path using the default schema #### Scenario: List template paths with custom schema - **WHEN** user runs `openspec templates --schema tdd` - **THEN** the system displays template paths for the specified schema #### Scenario: Templates JSON output - **WHEN** user runs `openspec templates --json` - **THEN** the system outputs JSON mapping artifact IDs to template paths #### Scenario: Template resolution source - **WHEN** displaying template paths - **THEN** the system indicates whether each template is from user override or package built-in ### Requirement: New Change Command The system SHALL create new change directories with validation. #### Scenario: Create valid change - **WHEN** user runs `openspec new change add-feature` - **THEN** the system creates `openspec/changes/add-feature/` directory #### Scenario: Invalid change name - **WHEN** user runs `openspec new change "Add Feature"` with invalid name - **THEN** the system displays validation error with guidance #### Scenario: Duplicate change name - **WHEN** user runs `openspec new change existing-change` for an existing change - **THEN** the system displays an error indicating the change already exists #### Scenario: Create with description - **WHEN** user runs `openspec new change add-feature --description "Add new feature"` - **THEN** the system creates the change directory with description in README.md ### Requirement: Schema Selection The system SHALL support custom schema selection for workflow commands. #### Scenario: Default schema - **WHEN** user runs workflow commands without `--schema` - **THEN** the system uses the "spec-driven" schema #### Scenario: Custom schema - **WHEN** user runs `openspec status --change --schema tdd` - **THEN** the system uses the specified schema for artifact graph #### Scenario: Unknown schema - **WHEN** user specifies an unknown schema - **THEN** the system displays an error listing available schemas ### Requirement: Output Formatting The system SHALL provide consistent output formatting. #### Scenario: Color output - **WHEN** terminal supports colors - **THEN** status indicators use colors: green (done), yellow (ready), red (blocked) #### Scenario: No color output - **WHEN** `--no-color` flag is used or NO_COLOR environment variable is set - **THEN** output uses text-only indicators without ANSI colors #### Scenario: Progress indication - **WHEN** loading change state takes time - **THEN** the system displays a spinner during loading ### Requirement: Experimental Isolation The system SHALL implement artifact workflow commands in isolation for easy removal. #### Scenario: Single file implementation - **WHEN** artifact workflow feature is implemented - **THEN** all commands are in `src/commands/artifact-workflow.ts` #### Scenario: Help text marking - **WHEN** user runs `--help` on any artifact workflow command - **THEN** help text indicates the command is experimental ================================================ FILE: openspec/changes/archive/2025-12-28-add-artifact-workflow-cli/tasks.md ================================================ ## 1. Core Command Implementation - [x] 1.1 Create `src/commands/artifact-workflow.ts` with all commands - [x] 1.2 Implement `status` command with text output - [x] 1.3 Implement `next` command with text output - [x] 1.4 Implement `instructions` command with text output - [x] 1.5 Implement `templates` command with text output - [x] 1.6 Implement `new change` subcommand using createChange() ## 2. CLI Registration - [x] 2.1 Register `status` command in `src/cli/index.ts` - [x] 2.2 Register `next` command in `src/cli/index.ts` - [x] 2.3 Register `instructions` command in `src/cli/index.ts` - [x] 2.4 Register `templates` command in `src/cli/index.ts` - [x] 2.5 Register `new` command group with `change` subcommand ## 3. Output Formatting - [x] 3.1 Add `--json` flag support to all commands - [x] 3.2 Add color-coded status indicators (done/ready/blocked) - [x] 3.3 Add progress spinner for loading operations - [x] 3.4 Support `--no-color` flag ## 4. Error Handling - [x] 4.1 Handle missing `--change` parameter with helpful error - [x] 4.2 Handle unknown change names with list of available changes - [x] 4.3 Handle unknown artifact names with valid options - [x] 4.4 Handle schema resolution errors ## 5. Options and Flags - [x] 5.1 Add `--schema` option for custom schema selection - [x] 5.2 Add `--description` option to `new change` command - [x] 5.3 Ensure options follow existing CLI patterns ## 6. Testing - [x] 6.1 Add smoke tests for each command - [x] 6.2 Test error cases (missing change, unknown artifact) - [x] 6.3 Test JSON output format - [x] 6.4 Test with different schemas ## 7. Documentation - [x] 7.1 Add help text for all commands marked as "Experimental" - [ ] 7.2 Update AGENTS.md with new commands (post-archive) ================================================ FILE: openspec/changes/archive/2025-12-28-add-instruction-loader/design.md ================================================ ## Context This is Slice 3 of the artifact-graph POC. We have: - `ArtifactGraph` class with graph operations (Slice 1) - `detectCompleted()` for filesystem-based state detection (Slice 1) - `resolveSchema()` for XDG schema resolution (Slice 1) - `createChange()` and `validateChangeName()` utilities (Slice 2) After `restructure-schema-directories` is implemented, schemas will be self-contained directories: ``` schemas// ├── schema.yaml └── templates/ └── *.md ``` This proposal adds template loading and instruction enrichment on top of that structure. ## Goals / Non-Goals **Goals:** - Load templates from schema directories - Enrich templates with change-specific context (dependency status) - Format change status for CLI output **Non-Goals:** - Template authoring UI - Dynamic template compilation/execution - Caching (keep it stateless like the rest) ## Decisions ### 1. Pure functions over classes Follow the pattern in `resolver.ts` and `state.ts`. Use a simple `ChangeContext` interface with pure functions: ```typescript interface ChangeContext { changeName: string; changeDir: string; schemaName: string; graph: ArtifactGraph; completed: CompletedSet; } function loadChangeContext(projectRoot: string, changeName: string, schemaName?: string): ChangeContext function loadTemplate(schemaName: string, templatePath: string): string function getInstructions(artifactId: string, context: ChangeContext): string function formatStatus(context: ChangeContext): string ``` **Why:** Matches existing codebase patterns. Easier to test. No hidden state. ### 2. Template resolution from schema directory Templates are loaded from the schema's `templates/` subdirectory: ```typescript function loadTemplate(schemaName: string, templatePath: string): string { const schemaDir = getSchemaDir(schemaName); // From resolver.ts const fullPath = path.join(schemaDir, 'templates', templatePath); return fs.readFileSync(fullPath, 'utf-8'); } ``` Resolution is handled by `getSchemaDir()` which already checks user override → package built-in. **Why:** Leverages existing schema resolution. Templates are co-located with schemas. ### 3. Template path from artifact definition The artifact's `template` field is a path relative to the schema's `templates/` directory: ```yaml artifacts: - id: proposal template: "proposal.md" # → schemas//templates/proposal.md ``` **Why:** Explicit, simple, no magic. ### 4. Minimal context injection Templates are markdown. Injection prepends a header section with context: ```markdown --- change: add-auth artifact: proposal schema: spec-driven output: openspec/changes/add-auth/proposal.md --- ## Dependencies - [x] (none - this is a root artifact) ## Next Steps After creating this artifact, you can work on: design, specs --- [original template content...] ``` **Why:** Simple string concatenation. No template engine dependency. Clear separation. ### 5. Status output format ```markdown ## Change: add-auth (spec-driven) | Artifact | Status | Output | |----------|--------|--------| | proposal | done | proposal.md | | specs | ready | specs/*.md | | design | blocked (needs: proposal) | design.md | | tasks | blocked (needs: specs, design) | tasks.md | ``` **Why:** Markdown table is readable in terminal and docs. Matches CLI output style. ## File Structure ``` src/core/artifact-graph/ ├── index.ts # Add new exports ├── template.ts # NEW: Template loading ├── context.ts # NEW: ChangeContext loading └── instructions.ts # NEW: Enrichment and formatting ``` ## Risks / Trade-offs **Dependency on restructure-schema-directories:** - This proposal requires the schema restructure to be done first - Mitigation: Clear dependency documented, implement in order **No template engine:** - Pro: Zero dependencies, simple code - Con: Limited expressiveness - Mitigation: Current use case only needs static templates + header injection ## Migration Plan N/A - new capability, no existing code to migrate. ## Open Questions None. ================================================ FILE: openspec/changes/archive/2025-12-28-add-instruction-loader/proposal.md ================================================ ## Why Slice 1 (artifact-graph) provides graph operations and state detection. Slice 2 (change-utils) provides change creation. We now need the ability to load templates for artifacts and enrich them with change-specific context so users/agents know what to create next. ## What Changes - Add template resolution from schema directories (uses structure from `restructure-schema-directories`) - Add instruction enrichment that injects change context into templates - Add status formatting for CLI output - New `instruction-loader` capability ## Dependencies - Requires `restructure-schema-directories` to be implemented first (schemas as directories with co-located templates) ## Impact - Affected specs: New `instruction-loader` spec - Affected code: `src/core/artifact-graph/` (new files) - Builds on: `artifact-graph` (Slice 1), uses `ArtifactGraph`, `detectCompleted`, `resolveSchema` ================================================ FILE: openspec/changes/archive/2025-12-28-add-instruction-loader/specs/instruction-loader/spec.md ================================================ # instruction-loader Specification ## Purpose Load templates from schema directories and enrich them with change-specific context for guiding artifact creation. ## ADDED Requirements ### Requirement: Template Loading The system SHALL load templates from schema directories. #### Scenario: Load template from schema directory - **WHEN** `loadTemplate(schemaName, templatePath)` is called - **THEN** the system loads the template from `schemas//templates/` #### Scenario: Template file not found - **WHEN** a template file does not exist in the schema's templates directory - **THEN** the system throws an error with the template path ### Requirement: Change Context Loading The system SHALL load change context combining graph and completion state. #### Scenario: Load context for existing change - **WHEN** `loadChangeContext(projectRoot, changeName)` is called for an existing change - **THEN** the system returns a context with graph, completed set, schema name, and change info #### Scenario: Load context with custom schema - **WHEN** `loadChangeContext(projectRoot, changeName, schemaName)` is called - **THEN** the system uses the specified schema instead of default #### Scenario: Load context for non-existent change directory - **WHEN** `loadChangeContext` is called for a non-existent change directory - **THEN** the system returns context with empty completed set ### Requirement: Template Enrichment The system SHALL enrich templates with change-specific context. #### Scenario: Include artifact metadata - **WHEN** instructions are generated for an artifact - **THEN** the output includes change name, artifact ID, schema name, and output path #### Scenario: Include dependency status - **WHEN** an artifact has dependencies - **THEN** the output shows each dependency with completion status (done/missing) #### Scenario: Include unlocked artifacts - **WHEN** instructions are generated - **THEN** the output includes which artifacts become available after this one #### Scenario: Root artifact indicator - **WHEN** an artifact has no dependencies - **THEN** the dependency section indicates this is a root artifact ### Requirement: Status Formatting The system SHALL format change status as readable output. #### Scenario: All artifacts completed - **WHEN** all artifacts are completed - **THEN** status shows all artifacts as "done" #### Scenario: Mixed completion status - **WHEN** some artifacts are completed - **THEN** status shows completed as "done", ready as "ready", blocked as "blocked" #### Scenario: Blocked artifact details - **WHEN** an artifact is blocked - **THEN** status shows which dependencies are missing #### Scenario: Include output paths - **WHEN** status is formatted - **THEN** each artifact shows its output path pattern ================================================ FILE: openspec/changes/archive/2025-12-28-add-instruction-loader/tasks.md ================================================ # Tasks ## Implementation Tasks - [x] Create `instruction-loader` spec in `openspec/specs/instruction-loader/spec.md` - [x] Implement `loadTemplate` function to load templates from schema directories - [x] Implement `loadChangeContext` function to combine graph and completion state - [x] Implement `generateInstructions` function to enrich templates with change context - [x] Implement `formatChangeStatus` function for readable status output - [x] Export new functions from `src/core/artifact-graph/index.ts` - [x] Add comprehensive tests in `test/core/artifact-graph/instruction-loader.test.ts` - [x] Verify build passes - [x] Verify all tests pass ================================================ FILE: openspec/changes/archive/2025-12-28-restructure-schema-directories/design.md ================================================ ## Context Built-in schemas are currently embedded as TypeScript objects: ```typescript // src/core/artifact-graph/builtin-schemas.ts export const SPEC_DRIVEN_SCHEMA: SchemaYaml = { name: 'spec-driven', version: 1, artifacts: [...] }; ``` This doesn't support templates co-located with schemas. The instruction loader (Slice 3) needs templates, and the cleanest approach is self-contained schema directories. ## Goals / Non-Goals **Goals:** - Schemas as self-contained directories (schema.yaml + templates/) - User overrides via XDG data directory - Simple 2-level resolution (user → package) - Templates co-located with their schema **Non-Goals:** - Shared template fallback (intentionally avoiding complexity) - Runtime schema compilation - Schema inheritance ## Decisions ### 1. Directory structure Each schema is a directory containing `schema.yaml` and `templates/`: ``` /schemas/ ├── spec-driven/ │ ├── schema.yaml │ └── templates/ │ ├── proposal.md │ ├── design.md │ ├── spec.md │ └── tasks.md └── tdd/ ├── schema.yaml └── templates/ ├── spec.md ├── test.md ├── implementation.md └── docs.md ``` **Why:** Self-contained like Helm charts. No cross-schema dependencies. Each schema owns its templates. ### 2. Resolution order (2 levels) ``` 1. ${XDG_DATA_HOME}/openspec/schemas//schema.yaml # User override 2. /schemas//schema.yaml # Built-in 3. Error (not found) ``` **Why:** Simple mental model. User can override entire schema directory or just parts. ### 3. Template path in schema.yaml The `template` field is relative to the schema's `templates/` directory: ```yaml # schemas/spec-driven/schema.yaml artifacts: - id: proposal template: "proposal.md" # → schemas/spec-driven/templates/proposal.md ``` **Why:** Paths are relative to the schema, not a global templates directory. ### 4. Resolve package directory via import.meta.url ```typescript function getPackageSchemasDir(): string { const currentFile = fileURLToPath(import.meta.url); // Navigate from src/core/artifact-graph/ to package root return path.join(path.dirname(currentFile), '..', '..', '..', 'schemas'); } ``` **Why:** Works in ESM. No hardcoded paths. ### 5. Keep schema.yaml format unchanged The YAML format stays the same - only the storage location changes: ```yaml name: spec-driven version: 1 description: Specification-driven development artifacts: - id: proposal generates: "proposal.md" template: "proposal.md" requires: [] ``` **Why:** No breaking changes to schema format. Just moving from TS to YAML files. ## Migration 1. Create `schemas/` directory at package root 2. Convert `SPEC_DRIVEN_SCHEMA` to `schemas/spec-driven/schema.yaml` 3. Convert `TDD_SCHEMA` to `schemas/tdd/schema.yaml` 4. Update `resolveSchema()` to load from directories 5. Remove `builtin-schemas.ts` 6. Update `listSchemas()` to scan directories ## Risks / Trade-offs **File I/O at runtime:** - Previously schemas were in-memory objects - Now requires reading YAML files - Mitigation: Schemas are small, loaded once per operation **Package distribution:** - Must ensure `schemas/` directory is included in npm package - Add to `files` in package.json ## Open Questions None. ================================================ FILE: openspec/changes/archive/2025-12-28-restructure-schema-directories/proposal.md ================================================ ## Why Currently, built-in schemas are embedded as TypeScript objects in `builtin-schemas.ts`. This works for schemas but doesn't support co-located templates. To enable self-contained schema packages (schema + templates together), we need to restructure schemas as directories. ## What Changes - **BREAKING (internal):** Move built-in schemas from embedded TS objects to actual directory structure - Schemas become directories containing `schema.yaml` + `templates/` - Update `resolveSchema()` to load from directory structure - Remove `builtin-schemas.ts` (replaced by file-based schemas) - Update resolution to check user dir → package dir ## Impact - Affected specs: `artifact-graph` (schema resolution changes) - Affected code: - Remove `src/core/artifact-graph/builtin-schemas.ts` - Update `src/core/artifact-graph/resolver.ts` - Add `schemas/` directory at package root - No external API changes (resolution still returns `SchemaYaml`) ================================================ FILE: openspec/changes/archive/2025-12-28-restructure-schema-directories/specs/artifact-graph/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Schema Loading The system SHALL load artifact graph definitions from YAML schema files within schema directories. #### Scenario: Valid schema loaded - **WHEN** a schema directory contains a valid `schema.yaml` file - **THEN** the system returns an ArtifactGraph with all artifacts and dependencies #### Scenario: Invalid schema rejected - **WHEN** a schema YAML file is missing required fields - **THEN** the system throws an error with a descriptive message #### Scenario: Cyclic dependencies detected - **WHEN** a schema contains cyclic artifact dependencies - **THEN** the system throws an error listing the artifact IDs in the cycle #### Scenario: Invalid dependency reference - **WHEN** an artifact's `requires` array references a non-existent artifact ID - **THEN** the system throws an error identifying the invalid reference #### Scenario: Duplicate artifact IDs rejected - **WHEN** a schema contains multiple artifacts with the same ID - **THEN** the system throws an error identifying the duplicate #### Scenario: Schema directory not found - **WHEN** resolving a schema name that has no corresponding directory - **THEN** the system throws an error listing available schemas ## ADDED Requirements ### Requirement: Schema Directory Structure The system SHALL support self-contained schema directories with co-located templates. #### Scenario: Schema with templates - **WHEN** a schema directory contains `schema.yaml` and `templates/` subdirectory - **THEN** artifacts can reference templates relative to the schema's templates directory #### Scenario: User schema override - **WHEN** a schema directory exists at `${XDG_DATA_HOME}/openspec/schemas//` - **THEN** the system uses that directory instead of the built-in #### Scenario: Built-in schema fallback - **WHEN** no user override exists for a schema - **THEN** the system uses the package built-in schema directory #### Scenario: List available schemas - **WHEN** listing schemas - **THEN** the system returns schema names from both user and package directories ================================================ FILE: openspec/changes/archive/2025-12-28-restructure-schema-directories/tasks.md ================================================ ## 1. Create Schema Directories - [ ] 1.1 Create `schemas/` directory at package root - [ ] 1.2 Create `schemas/spec-driven/schema.yaml` from `SPEC_DRIVEN_SCHEMA` - [ ] 1.3 Create `schemas/spec-driven/templates/` with placeholder templates - [ ] 1.4 Create `schemas/tdd/schema.yaml` from `TDD_SCHEMA` - [ ] 1.5 Create `schemas/tdd/templates/` with placeholder templates ## 2. Update Schema Resolution - [ ] 2.1 Add `getPackageSchemasDir()` function using `import.meta.url` - [ ] 2.2 Add `getSchemaDir(name)` to resolve schema directory path - [ ] 2.3 Update `resolveSchema()` to load from directory structure - [ ] 2.4 Update `listSchemas()` to scan directories instead of object keys - [ ] 2.5 Add tests for user override resolution - [ ] 2.6 Add tests for built-in fallback ## 3. Cleanup - [ ] 3.1 Remove `builtin-schemas.ts` - [ ] 3.2 Update `index.ts` exports (remove `BUILTIN_SCHEMAS`, `SPEC_DRIVEN_SCHEMA`, `TDD_SCHEMA`) - [ ] 3.3 Update any code that imports removed exports ## 4. Package Distribution - [ ] 4.1 Add `schemas/` to `files` array in `package.json` - [ ] 4.2 Verify schemas are included in built package ## 5. Fix Template Paths - [ ] 5.1 Update `template` field in schema.yaml files (remove `templates/` prefix) - [ ] 5.2 Ensure template paths are relative to schema's templates directory ================================================ FILE: openspec/changes/archive/2025-12-29-unify-change-state-model/design.md ================================================ # Design: Unify Change State Model ## Overview This change fixes two bugs with minimal disruption to the existing system: 1. **View bug**: Empty changes incorrectly shown as "Completed" 2. **Artifact workflow bug**: Commands fail on scaffolded changes ## Key Design Decision: Two Systems, Two Purposes The task-based and artifact-based systems serve **different purposes** and should coexist: | System | Purpose | Used By | |--------|---------|---------| | **Task Progress** | Track implementation work | `openspec view`, `openspec list` | | **Artifact Progress** | Track planning/spec work | `openspec status`, `openspec next` | We do NOT merge these systems. Instead, we fix each to work correctly in its domain. ## Change 1: Fix View Command ### Current Logic (Buggy) ```typescript // view.ts line 90 if (progress.total === 0 || progress.completed === progress.total) { completed.push({ name: entry.name }); } ``` Problem: `total === 0` means "no tasks defined yet", not "all tasks done". ### New Logic ```typescript if (progress.total === 0) { draft.push({ name: entry.name }); } else if (progress.completed === progress.total) { completed.push({ name: entry.name }); } else { active.push({ name: entry.name, progress }); } ``` ### View Output Change **Before:** ``` Completed Changes ───────────────── ✓ add-feature (all tasks done - correct) ✓ test-workflow (no tasks - WRONG) ``` **After:** ``` Draft Changes ───────────────── ○ test-workflow (no tasks yet) Active Changes ───────────────── ◉ add-scaffold [████░░░░] 3/7 tasks Completed Changes ───────────────── ✓ add-feature (all tasks done) ``` ## Change 2: Fix Artifact Workflow Discovery ### Current Logic (Buggy) ```typescript // artifact-workflow.ts - validateChangeExists() const activeChanges = await getActiveChangeIds(projectRoot); if (!activeChanges.includes(changeName)) { throw new Error(`Change '${changeName}' not found...`); } ``` Problem: `getActiveChangeIds()` requires `proposal.md`, but artifact workflow should work on empty directories to help create the first artifact. ### New Logic ```typescript async function validateChangeExists(changeName: string, projectRoot: string): Promise { const changePath = path.join(projectRoot, 'openspec', 'changes', changeName); // Check directory existence directly, not proposal.md if (!fs.existsSync(changePath) || !fs.statSync(changePath).isDirectory()) { // List available changes for helpful error message const entries = await fs.promises.readdir( path.join(projectRoot, 'openspec', 'changes'), { withFileTypes: true } ); const available = entries .filter(e => e.isDirectory() && e.name !== 'archive' && !e.name.startsWith('.')) .map(e => e.name); if (available.length === 0) { throw new Error('No changes found. Create one with: openspec new change '); } throw new Error(`Change '${changeName}' not found. Available:\n ${available.join('\n ')}`); } return changeName; } ``` ### Behavior Change ```bash # Before $ openspec new change foo $ openspec status --change foo Error: Change 'foo' not found. # After $ openspec new change foo $ openspec status --change foo Change: foo Progress: 0/4 artifacts complete [ ] proposal [-] specs (blocked by: proposal) [-] design (blocked by: proposal) [-] tasks (blocked by: specs, design) ``` ## What Stays the Same 1. **`getActiveChangeIds()`** - Still requires `proposal.md` (used by validate, show) 2. **`getArchivedChangeIds()`** - Unchanged 3. **Active/Completed semantics** - Still based on task checkboxes 4. **Validation** - Still requires `proposal.md` to have something to validate ## File Changes | File | Change | |------|--------| | `src/core/view.ts` | Add draft category, fix completion logic | | `src/commands/artifact-workflow.ts` | Update `validateChangeExists()` to use directory existence | | `test/commands/artifact-workflow.test.ts` | Add tests for scaffolded changes | ## Testing Strategy 1. **Unit test**: `validateChangeExists()` with scaffolded change 2. **View test**: Verify three categories render correctly 3. **Manual test**: Full workflow from `new change` → `status` → `view` ================================================ FILE: openspec/changes/archive/2025-12-29-unify-change-state-model/proposal.md ================================================ # Proposal: Unify Change State Model ## Problem Statement Two bugs create inconsistent behavior when working with changes: ### Bug 1: Empty changes shown as "Completed" in view ```typescript // view.ts line 90 if (progress.total === 0 || progress.completed === progress.total) { completed.push({ name: entry.name }); // BUG: total === 0 ≠ completed } ``` Result: `openspec new change foo && openspec view` shows `foo` as "Completed" when it has no content. ### Bug 2: Artifact workflow commands can't find scaffolded changes ```typescript // item-discovery.ts - getActiveChangeIds() const proposalPath = path.join(changesPath, entry.name, 'proposal.md'); await fs.access(proposalPath); // Only returns changes WITH proposal.md ``` Result: `openspec status --change foo` says "not found" even though the directory exists. ## Root Cause The system conflates two different concepts: | Concept | Question | Source of Truth | |---------|----------|-----------------| | **Planning Progress** | Are all spec documents created? | File existence (ArtifactGraph) | | **Implementation Progress** | Is the coding work done? | Task checkboxes (tasks.md) | ## Proposed Solution ### Fix 1: Add "Draft" state to view command Keep Active/Completed with their existing meanings, but fix the bug: | State | Criteria | Meaning | |-------|----------|---------| | **Draft** | No tasks.md OR `tasks.total === 0` | Still planning | | **Active** | `tasks.total > 0` AND `completed < total` | Implementing | | **Completed** | `tasks.total > 0` AND `completed === total` | Done | ### Fix 2: Artifact workflow uses directory existence Update `validateChangeExists()` to check if the directory exists, not if `proposal.md` exists. This allows the artifact workflow to guide users through creating their first artifact. ### Keep existing discovery functions `getActiveChangeIds()` continues to require `proposal.md` for backward compatibility with validation and other commands. ## What Changes | Command | Before | After | |---------|--------|-------| | `openspec view` | Empty = "Completed" | Empty = "Draft" | | `openspec status --change X` | Requires proposal.md | Works on any directory | | `openspec validate X` | Requires proposal.md | Unchanged (still requires it) | ## Breaking Changes ### Minimal Breaking Change 1. **`openspec view` output**: Empty changes move from "Completed" section to new "Draft" section ### Non-Breaking - Active/Completed semantics unchanged (still task-based) - `getActiveChangeIds()` unchanged - `openspec validate` unchanged - Archived changes unaffected ## Out of Scope - Merging task-based and artifact-based progress (they serve different purposes) - Changing what "Completed" means (it stays = all tasks done) - Adding artifact progress to view command (separate enhancement) - Shell tab completions for artifact workflow commands (not yet registered) ## Related Commands Analysis | Command | Uses `getActiveChangeIds()` | Should include scaffolded? | Change needed? | |---------|-----------------------------|-----------------------------|----------------| | `openspec view` | No (reads dirs directly) | Yes → Draft section | **Yes** | | `openspec list` | No (reads dirs directly) | Yes (shows "No tasks") | No | | `openspec status/next/instructions` | Yes | Yes | **Yes** | | `openspec validate` | Yes | No (can't validate empty) | No | | `openspec show` | Yes | No (nothing to show) | No | | Tab completions | Yes | Future enhancement | No | ## Success Criteria 1. `openspec new change foo && openspec view` shows `foo` in "Draft" section 2. `openspec new change foo && openspec status --change foo` works 3. Changes with all tasks done still show as "Completed" 4. All existing tests pass ================================================ FILE: openspec/changes/archive/2025-12-29-unify-change-state-model/specs/cli-artifact-workflow/spec.md ================================================ # cli-artifact-workflow Specification Delta ## MODIFIED Requirements ### Requirement: Status Command The system SHALL display artifact completion status for a change, including scaffolded (empty) changes. > **Fixes bug**: Previously required `proposal.md` to exist via `getActiveChangeIds()`. #### Scenario: Show status with all states - **WHEN** user runs `openspec status --change ` - **THEN** the system displays each artifact with status indicator: - `[x]` for completed artifacts - `[ ]` for ready artifacts - `[-]` for blocked artifacts (with missing dependencies listed) #### Scenario: Status shows completion summary - **WHEN** user runs `openspec status --change ` - **THEN** output includes completion percentage and count (e.g., "2/4 artifacts complete") #### Scenario: Status JSON output - **WHEN** user runs `openspec status --change --json` - **THEN** the system outputs JSON with changeName, schemaName, isComplete, and artifacts array #### Scenario: Status on scaffolded change - **WHEN** user runs `openspec status --change ` on a change with no artifacts - **THEN** system displays all artifacts with their status - **AND** root artifacts (no dependencies) show as ready `[ ]` - **AND** dependent artifacts show as blocked `[-]` #### Scenario: Missing change parameter - **WHEN** user runs `openspec status` without `--change` - **THEN** the system displays an error with list of available changes - **AND** includes scaffolded changes (directories without proposal.md) #### Scenario: Unknown change - **WHEN** user runs `openspec status --change unknown-id` - **AND** directory `openspec/changes/unknown-id/` does not exist - **THEN** the system displays an error listing all available change directories ### Requirement: Next Command The system SHALL show which artifacts are ready to be created, including for scaffolded changes. #### Scenario: Show ready artifacts - **WHEN** user runs `openspec next --change ` - **THEN** the system lists artifacts whose dependencies are all satisfied #### Scenario: No artifacts ready - **WHEN** all artifacts are either completed or blocked - **THEN** the system indicates no artifacts are ready (with explanation) #### Scenario: All artifacts complete - **WHEN** all artifacts in the change are completed - **THEN** the system indicates the change is complete #### Scenario: Next JSON output - **WHEN** user runs `openspec next --change --json` - **THEN** the system outputs JSON array of ready artifact IDs #### Scenario: Next on scaffolded change - **WHEN** user runs `openspec next --change ` on a change with no artifacts - **THEN** system shows root artifacts (e.g., "proposal") as ready to create ### Requirement: Instructions Command The system SHALL output enriched instructions for creating an artifact, including for scaffolded changes. #### Scenario: Show enriched instructions - **WHEN** user runs `openspec instructions --change ` - **THEN** the system outputs: - Artifact metadata (ID, output path, description) - Template content - Dependency status (done/missing) - Unlocked artifacts (what becomes available after completion) #### Scenario: Instructions JSON output - **WHEN** user runs `openspec instructions --change --json` - **THEN** the system outputs JSON matching ArtifactInstructions interface #### Scenario: Unknown artifact - **WHEN** user runs `openspec instructions unknown-artifact --change ` - **THEN** the system displays an error listing valid artifact IDs for the schema #### Scenario: Artifact with unmet dependencies - **WHEN** user requests instructions for a blocked artifact - **THEN** the system displays instructions with a warning about missing dependencies #### Scenario: Instructions on scaffolded change - **WHEN** user runs `openspec instructions proposal --change ` on a scaffolded change - **THEN** system outputs template and metadata for creating the proposal - **AND** does not require any artifacts to already exist ================================================ FILE: openspec/changes/archive/2025-12-29-unify-change-state-model/specs/cli-view/spec.md ================================================ # cli-view Specification Delta ## ADDED Requirements ### Requirement: Draft Changes Display The dashboard SHALL display changes without tasks in a separate "Draft" section. #### Scenario: Draft changes listing - **WHEN** there are changes with no tasks.md or zero tasks defined - **THEN** system shows them in a "Draft Changes" section - **AND** uses a distinct indicator (e.g., `○`) to show draft status #### Scenario: Draft section ordering - **WHEN** multiple draft changes exist - **THEN** system sorts them alphabetically by name ## MODIFIED Requirements ### Requirement: Completed Changes Display The dashboard SHALL list completed changes in a separate section, only showing changes with ALL tasks completed. > **Fixes bug**: Previously, changes with `total === 0` were incorrectly shown as completed. #### Scenario: Completed changes listing - **WHEN** there are changes with `tasks.total > 0` AND `tasks.completed === tasks.total` - **THEN** system shows them with checkmark indicators in a dedicated section #### Scenario: Mixed completion states - **WHEN** some changes are complete and others active - **THEN** system separates them into appropriate sections #### Scenario: Empty changes not completed - **WHEN** a change has no tasks.md or zero tasks defined - **THEN** system does NOT show it in "Completed Changes" section - **AND** shows it in "Draft Changes" section instead ### Requirement: Summary Section The dashboard SHALL display a summary section with key project metrics, including draft change count. #### Scenario: Complete summary display - **WHEN** dashboard is rendered with specs and changes - **THEN** system shows total number of specifications and requirements - **AND** shows number of draft changes - **AND** shows number of active changes in progress - **AND** shows number of completed changes - **AND** shows overall task progress percentage #### Scenario: Empty project summary - **WHEN** no specs or changes exist - **THEN** summary shows zero counts for all metrics ================================================ FILE: openspec/changes/archive/2025-12-29-unify-change-state-model/tasks.md ================================================ # Tasks: Unify Change State Model ## Phase 1: Fix Artifact Workflow Discovery - [x] Update `validateChangeExists()` in `artifact-workflow.ts` to check directory existence instead of using `getActiveChangeIds()` - [x] Update error message to list all change directories (not just those with proposal.md) - [x] Add test for `openspec status --change ` - [x] Add test for `openspec next --change ` - [x] Add test for `openspec instructions proposal --change ` ## Phase 2: Fix View Command - [x] Update `getChangesData()` in `view.ts` to return three categories: draft, active, completed - [x] Fix completion logic: `total === 0` → draft, not completed - [x] Add "Draft Changes" section to dashboard rendering - [x] Update summary to include draft count - [x] Add test for draft changes appearing correctly in view ## Phase 3: Cleanup and Validation - [x] Clean up test changes (`test-workflow`, `test-workflow-2`) - [x] Run full test suite - [x] Manual test: `openspec new change foo && openspec status --change foo` - [x] Manual test: `openspec new change foo && openspec view` shows foo in Draft - [x] Validate with `openspec validate unify-change-state-model --strict` ================================================ FILE: openspec/changes/archive/2025-12-30-add-antigravity-support/proposal.md ================================================ ## Why Google is rolling out Antigravity, a Windsurf-derived IDE that discovers workflows from `.agent/workflows/*.md`. Today OpenSpec can only scaffold slash commands for Windsurf directories, so Antigravity users cannot run the proposal/apply/archive flows from the IDE. ## What Changes - Add Antigravity as a selectable native tool in `openspec init` so it creates `.agent/workflows/openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` with YAML frontmatter containing only a `description` field plus the standard OpenSpec-managed body. - Ensure `openspec update` refreshes the body of any existing Antigravity workflows inside `.agent/workflows/` without creating missing files, mirroring the Windsurf behavior. - Share e2e/template coverage confirming the generator writes the proper directory, filename casing, and frontmatter format so Antigravity picks up the workflows. ## Impact - Affected specs: `specs/cli-init`, `specs/cli-update` - Expected code: CLI init/update tool registries, slash-command templates, associated tests ================================================ FILE: openspec/changes/archive/2025-12-30-add-antigravity-support/specs/cli-init/spec.md ================================================ # Delta for CLI Init ## MODIFIED Requirements ### Requirement: Slash Command Configuration The init command SHALL generate slash command files for supported editors using shared templates. #### Scenario: Generating slash commands for Antigravity - **WHEN** the user selects Antigravity during initialization - **THEN** create `.agent/workflows/openspec-proposal.md`, `.agent/workflows/openspec-apply.md`, and `.agent/workflows/openspec-archive.md` - **AND** ensure each file begins with YAML frontmatter that contains only a `description: ` field followed by the shared OpenSpec workflow instructions wrapped in managed markers - **AND** populate the workflow body with the same proposal/apply/archive guidance used for other tools so Antigravity behaves like Windsurf while pointing to the `.agent/workflows/` directory #### Scenario: Generating slash commands for Claude Code - **WHEN** the user selects Claude Code during initialization - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for CodeBuddy Code - **WHEN** the user selects CodeBuddy Code during initialization - **THEN** create `.codebuddy/commands/openspec/proposal.md`, `.codebuddy/commands/openspec/apply.md`, and `.codebuddy/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cline - **WHEN** the user selects Cline during initialization - **THEN** create `.clinerules/openspec-proposal.md`, `.clinerules/openspec-apply.md`, and `.clinerules/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include Cline-specific Markdown heading frontmatter - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Crush - **WHEN** the user selects Crush during initialization - **THEN** create `.crush/commands/openspec/proposal.md`, `.crush/commands/openspec/apply.md`, and `.crush/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include Crush-specific frontmatter with OpenSpec category and tags - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cursor - **WHEN** the user selects Cursor during initialization - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Factory Droid - **WHEN** the user selects Factory Droid during initialization - **THEN** create `.factory/commands/openspec-proposal.md`, `.factory/commands/openspec-apply.md`, and `.factory/commands/openspec-archive.md` - **AND** populate each file from shared templates that include Factory-compatible YAML frontmatter for the `description` and `argument-hint` fields - **AND** include the `$ARGUMENTS` placeholder in the template body so droid receives any user-supplied input - **AND** wrap the generated content in OpenSpec managed markers so `openspec update` can safely refresh the commands #### Scenario: Generating slash commands for OpenCode - **WHEN** the user selects OpenCode during initialization - **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Windsurf - **WHEN** the user selects Windsurf during initialization - **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Kilo Code - **WHEN** the user selects Kilo Code during initialization - **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Codex - **WHEN** the user selects Codex during initialization - **THEN** create global prompt files at `~/.codex/prompts/openspec-proposal.md`, `~/.codex/prompts/openspec-apply.md`, and `~/.codex/prompts/openspec-archive.md` (or under `$CODEX_HOME/prompts` if set) - **AND** populate each file from shared templates that map the first numbered placeholder (`$1`) to the primary user input (e.g., change identifier or question text) - **AND** wrap the generated content in OpenSpec markers so `openspec update` can refresh the prompts without touching surrounding custom notes #### Scenario: Generating slash commands for GitHub Copilot - **WHEN** the user selects GitHub Copilot during initialization - **THEN** create `.github/prompts/openspec-proposal.prompt.md`, `.github/prompts/openspec-apply.prompt.md`, and `.github/prompts/openspec-archive.prompt.md` - **AND** populate each file with YAML frontmatter containing a `description` field that summarizes the workflow stage - **AND** include `$ARGUMENTS` placeholder to capture user input - **AND** wrap the shared template body with OpenSpec markers so `openspec update` can refresh the content - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Gemini CLI - **WHEN** the user selects Gemini CLI during initialization - **THEN** create `.gemini/commands/openspec/proposal.toml`, `.gemini/commands/openspec/apply.toml`, and `.gemini/commands/openspec/archive.toml` - **AND** populate each file as TOML that sets a stage-specific `description = ""` and a multi-line `prompt = """` block with the shared OpenSpec template - **AND** wrap the OpenSpec managed markers (`` / ``) inside the `prompt` value so `openspec update` can safely refresh the body between markers without touching the TOML framing - **AND** ensure the slash-command copy matches the existing proposal/apply/archive templates used by other tools #### Scenario: Generating slash commands for iFlow CLI - **WHEN** the user selects iFlow CLI during initialization - **THEN** create `.iflow/commands/openspec-proposal.md`, `.iflow/commands/openspec-apply.md`, and `.iflow/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include YAML frontmatter with `name`, `id`, `category`, and `description` fields for each command - **AND** wrap the generated content in OpenSpec managed markers so `openspec update` can safely refresh the commands - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for RooCode - **WHEN** the user selects RooCode during initialization - **THEN** create `.roo/commands/openspec-proposal.md`, `.roo/commands/openspec-apply.md`, and `.roo/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include simple Markdown headings (e.g., `# OpenSpec: Proposal`) without YAML frontmatter - **AND** wrap the generated content in OpenSpec managed markers where applicable so `openspec update` can safely refresh the commands - **AND** each template includes instructions for the relevant OpenSpec workflow stage ================================================ FILE: openspec/changes/archive/2025-12-30-add-antigravity-support/specs/cli-update/spec.md ================================================ # Delta for CLI Update ## MODIFIED Requirements ### Requirement: Slash Command Updates The update command SHALL refresh existing slash command files for configured tools without creating new ones, and ensure the OpenCode archive command accepts change ID arguments. #### Scenario: Updating slash commands for Antigravity - **WHEN** `.agent/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh the OpenSpec-managed portion of each file so the workflow copy matches other tools while preserving the existing single-field `description` frontmatter - **AND** skip creating any missing workflow files during update, mirroring the behavior for Windsurf and other IDEs #### Scenario: Updating slash commands for Claude Code - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for CodeBuddy Code - **WHEN** `.codebuddy/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Cline - **WHEN** `.clinerules/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** include Cline-specific Markdown heading frontmatter - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Crush - **WHEN** `.crush/commands/` contains `openspec/proposal.md`, `openspec/apply.md`, and `openspec/archive.md` - **THEN** refresh each file using shared templates - **AND** include Crush-specific frontmatter with OpenSpec category and tags - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Cursor - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Factory Droid - **WHEN** `.factory/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using the shared Factory templates that include YAML frontmatter for the `description` and `argument-hint` fields - **AND** ensure the template body retains the `$ARGUMENTS` placeholder so user input keeps flowing into droid - **AND** update only the content inside the OpenSpec managed markers, leaving any unmanaged notes untouched - **AND** skip creating missing files during update #### Scenario: Updating slash commands for OpenCode - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage - **AND** ensure the archive command includes `$ARGUMENTS` placeholder in frontmatter for accepting change ID arguments #### Scenario: Updating slash commands for Windsurf - **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage - **AND** skip creating missing files (the update command only refreshes what already exists) #### Scenario: Updating slash commands for Kilo Code - **WHEN** `.kilocode/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage - **AND** skip creating missing files (the update command only refreshes what already exists) #### Scenario: Updating slash commands for Codex - **GIVEN** the global Codex prompt directory contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **WHEN** a user runs `openspec update` - **THEN** refresh each file using the shared slash-command templates (including placeholder guidance) - **AND** preserve any unmanaged content outside the OpenSpec marker block - **AND** skip creation when a Codex prompt file is missing #### Scenario: Updating slash commands for GitHub Copilot - **WHEN** `.github/prompts/` contains `openspec-proposal.prompt.md`, `openspec-apply.prompt.md`, and `openspec-archive.prompt.md` - **THEN** refresh each file using shared templates while preserving the YAML frontmatter - **AND** update only the OpenSpec-managed block between markers - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Gemini CLI - **WHEN** `.gemini/commands/openspec/` contains `proposal.toml`, `apply.toml`, and `archive.toml` - **THEN** refresh the body of each file using the shared proposal/apply/archive templates - **AND** replace only the content between `` and `` markers inside the `prompt = """` block so the TOML framing (`description`, `prompt`) stays intact - **AND** skip creating any missing `.toml` files during update; only pre-existing Gemini commands are refreshed #### Scenario: Updating slash commands for iFlow CLI - **WHEN** `.iflow/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** preserve the YAML frontmatter with `name`, `id`, `category`, and `description` fields - **AND** update only the OpenSpec-managed block between markers - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Missing slash command file - **WHEN** a tool lacks a slash command file - **THEN** do not create a new file during update ================================================ FILE: openspec/changes/archive/2025-12-30-add-antigravity-support/tasks.md ================================================ ## 1. CLI init support - [x] 1.1 Surface Antigravity in the native-tool picker (interactive + `--tools`) so it toggles alongside other IDEs. - [x] 1.2 Generate `.agent/workflows/openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` with YAML frontmatter restricted to a single `description` field for each stage and wrap the body in OpenSpec markers. - [x] 1.3 Confirm workspace scaffolding covers missing directory creation and re-run scenarios so repeated init refreshes the managed block. ## 2. CLI update support - [x] 2.1 Detect existing Antigravity workflow files during `openspec update` and refresh only the managed body, skipping creation when files are missing. - [x] 2.2 Ensure update logic preserves the `description` frontmatter block exactly as written by init, including case and spacing, and refreshes body templates alongside other tools. ## 3. Templates and tests - [x] 3.1 Add shared template entries for Antigravity that reuse the Windsurf copy but target `.agent/workflows` plus the description-only frontmatter requirement. - [x] 3.2 Expand automated coverage (unit or integration) verifying init and update produce the expected file paths and frontmatter + body markers for Antigravity. ================================================ FILE: openspec/changes/archive/2025-12-30-fix-cline-workflows-implementation/proposal.md ================================================ ## Why The Cline implementation was architecturally incorrect. According to Cline's official documentation, Cline uses workflows for on-demand automation and rules for behavioral guidelines. The OpenSpec slash commands are procedural workflows (scaffold → implement → archive), not behavioral rules, so they should be placed in `.clinerules/workflows/` instead of `.clinerules/`. ## What Changes - Update ClineSlashCommandConfigurator to use `.clinerules/workflows/` paths instead of `.clinerules/` paths - Update all tests to expect the correct workflow file locations - Update README.md documentation to reflect workflows instead of rules - **BREAKING**: Existing Cline users will need to re-run `openspec init` to get the corrected workflow files ## Impact - Affected specs: cli-init, cli-update (corrected Cline workflow paths) - Affected code: `src/core/configurators/slash/cline.ts`, test files, README.md - Modified files: `.clinerules/workflows/openspec-*.md` (moved from `.clinerules/openspec-*.md`) ================================================ FILE: openspec/changes/archive/2025-12-30-fix-cline-workflows-implementation/specs/cli-init/spec.md ================================================ # Delta for CLI Init ## MODIFIED Requirements ### Requirement: Slash Command Configuration The init command SHALL generate slash command files for supported editors using shared templates. #### Scenario: Generating slash commands for Antigravity - **WHEN** the user selects Antigravity during initialization - **THEN** create `.agent/workflows/openspec-proposal.md`, `.agent/workflows/openspec-apply.md`, and `.agent/workflows/openspec-archive.md` - **AND** ensure each file begins with YAML frontmatter that contains only a `description: ` field followed by the shared OpenSpec workflow instructions wrapped in managed markers - **AND** populate the workflow body with the same proposal/apply/archive guidance used for other tools so Antigravity behaves like Windsurf while pointing to the `.agent/workflows/` directory #### Scenario: Generating slash commands for Claude Code - **WHEN** the user selects Claude Code during initialization - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for CodeBuddy Code - **WHEN** the user selects CodeBuddy Code during initialization - **THEN** create `.codebuddy/commands/openspec/proposal.md`, `.codebuddy/commands/openspec/apply.md`, and `.codebuddy/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cline - **WHEN** the user selects Cline during initialization - **THEN** create `.clinerules/workflows/openspec-proposal.md`, `.clinerules/workflows/openspec-apply.md`, and `.clinerules/workflows/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include Cline-specific Markdown heading frontmatter - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Crush - **WHEN** the user selects Crush during initialization - **THEN** create `.crush/commands/openspec/proposal.md`, `.crush/commands/openspec/apply.md`, and `.crush/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include Crush-specific frontmatter with OpenSpec category and tags - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cursor - **WHEN** the user selects Cursor during initialization - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Factory Droid - **WHEN** the user selects Factory Droid during initialization - **THEN** create `.factory/commands/openspec-proposal.md`, `.factory/commands/openspec-apply.md`, and `.factory/commands/openspec-archive.md` - **AND** populate each file from shared templates that include Factory-compatible YAML frontmatter for the `description` and `argument-hint` fields - **AND** include the `$ARGUMENTS` placeholder in the template body so droid receives any user-supplied input - **AND** wrap the generated content in OpenSpec managed markers so `openspec update` can safely refresh the commands #### Scenario: Generating slash commands for OpenCode - **WHEN** the user selects OpenCode during initialization - **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Windsurf - **WHEN** the user selects Windsurf during initialization - **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Kilo Code - **WHEN** the user selects Kilo Code during initialization - **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Codex - **WHEN** the user selects Codex during initialization - **THEN** create global prompt files at `~/.codex/prompts/openspec-proposal.md`, `~/.codex/prompts/openspec-apply.md`, and `~/.codex/prompts/openspec-archive.md` (or under `$CODEX_HOME/prompts` if set) - **AND** populate each file from shared templates that map the first numbered placeholder (`$1`) to the primary user input (e.g., change identifier or question text) - **AND** wrap the generated content in OpenSpec markers so `openspec update` can refresh the prompts without touching surrounding custom notes #### Scenario: Generating slash commands for GitHub Copilot - **WHEN** the user selects GitHub Copilot during initialization - **THEN** create `.github/prompts/openspec-proposal.prompt.md`, `.github/prompts/openspec-apply.prompt.md`, and `.github/prompts/openspec-archive.prompt.md` - **AND** populate each file with YAML frontmatter containing a `description` field that summarizes the workflow stage - **AND** include `$ARGUMENTS` placeholder to capture user input - **AND** wrap the shared template body with OpenSpec markers so `openspec update` can refresh the content - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Gemini CLI - **WHEN** the user selects Gemini CLI during initialization - **THEN** create `.gemini/commands/openspec/proposal.toml`, `.gemini/commands/openspec/apply.toml`, and `.gemini/commands/openspec/archive.toml` - **AND** populate each file as TOML that sets a stage-specific `description = ""` and a multi-line `prompt = """` block with the shared OpenSpec template - **AND** wrap the OpenSpec managed markers (`` / ``) inside the `prompt` value so `openspec update` can safely refresh the body between markers without touching the TOML framing - **AND** ensure the slash-command copy matches the existing proposal/apply/archive templates used by other tools #### Scenario: Generating slash commands for iFlow CLI - **WHEN** the user selects iFlow CLI during initialization - **THEN** create `.iflow/commands/openspec-proposal.md`, `.iflow/commands/openspec-apply.md`, and `.iflow/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include YAML frontmatter with `name`, `id`, `category`, and `description` fields for each command - **AND** wrap the generated content in OpenSpec managed markers so `openspec update` can safely refresh the commands - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for RooCode - **WHEN** the user selects RooCode during initialization - **THEN** create `.roo/commands/openspec-proposal.md`, `.roo/commands/openspec-apply.md`, and `.roo/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include simple Markdown headings (e.g., `# OpenSpec: Proposal`) without YAML frontmatter - **AND** wrap the generated content in OpenSpec managed markers where applicable so `openspec update` can safely refresh the commands - **AND** each template includes instructions for the relevant OpenSpec workflow stage ================================================ FILE: openspec/changes/archive/2025-12-30-fix-cline-workflows-implementation/specs/cli-update/spec.md ================================================ # Delta for CLI Update ## MODIFIED Requirements ### Requirement: Slash Command Updates The update command SHALL refresh existing slash command files for configured tools without creating new ones, and ensure the OpenCode archive command accepts change ID arguments. #### Scenario: Updating slash commands for Antigravity - **WHEN** `.agent/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh the OpenSpec-managed portion of each file so the workflow copy matches other tools while preserving the existing single-field `description` frontmatter - **AND** skip creating any missing workflow files during update, mirroring the behavior for Windsurf and other IDEs #### Scenario: Updating slash commands for Claude Code - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for CodeBuddy Code - **WHEN** `.codebuddy/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Cline - **WHEN** `.clinerules/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** include Cline-specific Markdown heading frontmatter - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Crush - **WHEN** `.crush/commands/` contains `openspec/proposal.md`, `openspec/apply.md`, and `openspec/archive.md` - **THEN** refresh each file using shared templates - **AND** include Crush-specific frontmatter with OpenSpec category and tags - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Cursor - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Factory Droid - **WHEN** `.factory/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using the shared Factory templates that include YAML frontmatter for the `description` and `argument-hint` fields - **AND** ensure the template body retains the `$ARGUMENTS` placeholder so user input keeps flowing into droid - **AND** update only the content inside the OpenSpec managed markers, leaving any unmanaged notes untouched - **AND** skip creating missing files during update #### Scenario: Updating slash commands for OpenCode - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage - **AND** ensure the archive command includes `$ARGUMENTS` placeholder in frontmatter for accepting change ID arguments #### Scenario: Updating slash commands for Windsurf - **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage - **AND** skip creating missing files (the update command only refreshes what already exists) #### Scenario: Updating slash commands for Kilo Code - **WHEN** `.kilocode/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates wrapped in OpenSpec markers - **AND** ensure templates include instructions for the relevant workflow stage - **AND** skip creating missing files (the update command only refreshes what already exists) #### Scenario: Updating slash commands for Codex - **GIVEN** the global Codex prompt directory contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **WHEN** a user runs `openspec update` - **THEN** refresh each file using the shared slash-command templates (including placeholder guidance) - **AND** preserve any unmanaged content outside the OpenSpec marker block - **AND** skip creation when a Codex prompt file is missing #### Scenario: Updating slash commands for GitHub Copilot - **WHEN** `.github/prompts/` contains `openspec-proposal.prompt.md`, `openspec-apply.prompt.md`, and `openspec-archive.prompt.md` - **THEN** refresh each file using shared templates while preserving the YAML frontmatter - **AND** update only the OpenSpec-managed block between markers - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Gemini CLI - **WHEN** `.gemini/commands/openspec/` contains `proposal.toml`, `apply.toml`, and `archive.toml` - **THEN** refresh the body of each file using the shared proposal/apply/archive templates - **AND** replace only the content between `` and `` markers inside the `prompt = """` block so the TOML framing (`description`, `prompt`) stays intact - **AND** skip creating any missing `.toml` files during update; only pre-existing Gemini commands are refreshed #### Scenario: Updating slash commands for iFlow CLI - **WHEN** `.iflow/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** preserve the YAML frontmatter with `name`, `id`, `category`, and `description` fields - **AND** update only the OpenSpec-managed block between markers - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Missing slash command file - **WHEN** a tool lacks a slash command file - **THEN** do not create a new file during update ================================================ FILE: openspec/changes/archive/2025-12-30-fix-cline-workflows-implementation/tasks.md ================================================ ## 1. Update ClineSlashCommandConfigurator - [x] Change FILE_PATHS in `src/core/configurators/slash/cline.ts` from `.clinerules/openspec-*.md` to `.clinerules/workflows/openspec-*.md` ## 2. Update Tests - [x] Update "should refresh existing Cline rule files" test in `test/core/update.test.ts` to use workflow paths - [x] Update "should create Cline rule files with templates" test in `test/core/init.test.ts` to use workflow paths ## 3. Update Documentation - [x] Update README.md table to show "Workflows in `.clinerules/workflows/` directory" for Cline ## 4. Validate Changes - [x] Ensure all tests pass with the new paths - [x] Verify the change follows OpenSpec conventions ================================================ FILE: openspec/changes/archive/2026-01-06-add-agent-schema-selection/proposal.md ================================================ ## Why With per-change schema metadata in place (see `add-per-change-schema-metadata`), agents can now create changes with different workflow schemas. However, the agent skills are still hardcoded to `spec-driven` artifacts and don't offer schema selection to users. ## What Changes **Scope: Experimental artifact workflow agent skills** **Depends on:** `add-per-change-schema-metadata` (must be implemented first) - Update `openspec-new-change` skill to prompt user for schema selection - Update `openspec-continue-change` skill to work with any schema's artifacts - Update `openspec-apply-change` skill to handle schema-specific task structures - Add schema descriptions to help users choose appropriate workflow ## Capabilities ### Modified Capabilities - `cli-artifact-workflow`: Agent skills support dynamic schema selection ## Impact - **Affected code**: `src/core/templates/skill-templates.ts` - **User experience**: Users can choose TDD, spec-driven, or future workflows when starting a change - **Agent behavior**: Skills read artifact list from schema rather than hardcoding - **Backward compatible**: Default remains `spec-driven` if user doesn't choose ================================================ FILE: openspec/changes/archive/2026-01-06-add-agent-schema-selection/tasks.md ================================================ ## Prerequisites - [x] 0.1 Implement `add-per-change-schema-metadata` change first ## 1. Schema Discovery - [x] 1.1 Add CLI command or helper to list schemas with descriptions (for agent use) - [x] 1.2 Ensure `openspec templates --schema ` returns artifact list for any schema ## 2. Update New Change Skill - [x] 2.1 Add schema selection prompt using AskUserQuestion tool - [x] 2.2 Present available schemas with descriptions (spec-driven, tdd, etc.) - [x] 2.3 Pass selected schema to `openspec new change --schema ` - [x] 2.4 Update output to show which schema/workflow was selected ## 3. Update Continue Change Skill - [x] 3.1 Remove hardcoded artifact references (proposal, specs, design, tasks) - [x] 3.2 Read artifact list dynamically from `openspec status --json` - [x] 3.3 Adjust artifact creation guidelines to be schema-agnostic - [x] 3.4 Handle schema-specific artifact types (e.g., TDD's `tests` artifact) ## 4. Update Apply Change Skill - [x] 4.1 Make task detection work with different schema structures - [x] 4.2 Adjust context file reading for schema-specific artifacts ## 5. Documentation - [x] 5.1 Add schema descriptions to help text or skill instructions - [x] 5.2 Document when to use each schema (TDD for bug fixes, spec-driven for features, etc.) ================================================ FILE: openspec/changes/archive/2026-01-06-add-per-change-schema-metadata/design.md ================================================ ## Context The experimental artifact workflow supports multiple schemas (`spec-driven`, `tdd`), but schema selection must be passed on every command. This creates friction for agents and users. We need a lightweight metadata file to persist the schema choice per change. ## Goals / Non-Goals **Goals:** - Store schema choice once at change creation - Auto-detect schema in experimental workflow commands - Maintain backward compatibility (no metadata = default) - Validate metadata with Zod schema **Non-Goals:** - Migrate existing changes (they use default) - Extend to legacy commands - Store additional metadata beyond schema (keep minimal for now) ## Decisions ### Decision: Zod Schema Design The metadata file (`.openspec.yaml`) will be validated with this Zod schema: ```typescript // src/core/artifact-graph/types.ts (or new metadata.ts) import { z } from 'zod'; import { listSchemas } from './resolver.js'; /** * Schema for per-change metadata stored in .openspec.yaml */ export const ChangeMetadataSchema = z.object({ // Required: which workflow schema this change uses schema: z.string().min(1, { message: 'schema is required' }).refine( (val) => listSchemas().includes(val), (val) => ({ message: `Unknown schema '${val}'. Available: ${listSchemas().join(', ')}` }) ), // Optional: creation timestamp (ISO date string) created: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, { message: 'created must be YYYY-MM-DD format' }).optional(), }); export type ChangeMetadata = z.infer; ``` **Rationale:** - `schema` is required and validated against available schemas at parse time - `created` is optional, ISO date format for consistency - Minimal fields - can extend later without breaking existing files - Follows existing codebase pattern (see `ArtifactSchema`, `SchemaYamlSchema`) ### Decision: File Location and Format **Location:** `openspec/changes//.openspec.yaml` **Format:** ```yaml schema: tdd created: 2025-01-05 ``` **Alternatives considered:** - `change.yaml` - less hidden, but clutters directory - Frontmatter in `proposal.md` - couples to proposal existence - `openspec.json` - YAML matches existing schema files ### Decision: Read/Write Functions ```typescript // src/utils/change-metadata.ts import * as fs from 'node:fs'; import * as path from 'node:path'; import * as yaml from 'yaml'; import { ChangeMetadataSchema, type ChangeMetadata } from '../core/artifact-graph/types.js'; const METADATA_FILENAME = '.openspec.yaml'; export function writeChangeMetadata( changeDir: string, metadata: ChangeMetadata ): void { // Validate before writing const validated = ChangeMetadataSchema.parse(metadata); const content = yaml.stringify(validated); fs.writeFileSync(path.join(changeDir, METADATA_FILENAME), content); } export function readChangeMetadata( changeDir: string ): ChangeMetadata | null { const metaPath = path.join(changeDir, METADATA_FILENAME); if (!fs.existsSync(metaPath)) { return null; } const content = fs.readFileSync(metaPath, 'utf-8'); const parsed = yaml.parse(content); // Validate and return (throws ZodError if invalid) return ChangeMetadataSchema.parse(parsed); } ``` ### Decision: Schema Resolution Order When determining which schema to use: 1. **Explicit `--schema` flag** (highest priority - user override) 2. **`.openspec.yaml` metadata** (persisted choice) 3. **Default `spec-driven`** (fallback) ```typescript function resolveSchemaForChange( changeDir: string, explicitSchema?: string ): string { if (explicitSchema) return explicitSchema; const metadata = readChangeMetadata(changeDir); if (metadata?.schema) return metadata.schema; return 'spec-driven'; } ``` ## Risks / Trade-offs - **Extra file per change** → Minimal overhead, hidden file - **YAML parsing dependency** → Already using `yaml` package for schema files - **Schema validation at read time** → Fail fast with clear error if corrupted ## Migration Plan No migration needed: - Existing changes without `.openspec.yaml` continue to work (use default) - New changes created with `openspec new change --schema X` get metadata file ## Open Questions - Should `openspec new change` prompt for schema interactively if not specified? (Leaning no - default is fine) ================================================ FILE: openspec/changes/archive/2026-01-06-add-per-change-schema-metadata/proposal.md ================================================ ## Why Currently, the schema (workflow type) must be passed via `--schema` flag on every experimental workflow command. This is repetitive and error-prone. Agents have no way to know which schema a change uses, so they default to `spec-driven` and cannot leverage alternative workflows like `tdd`. ## What Changes **Scope: Experimental artifact workflow only** (`openspec new change`, `openspec status`, `openspec instructions`, `openspec templates`) - Store schema choice in `.openspec.yaml` metadata file when creating a change via `openspec new change` - Auto-detect schema from metadata in experimental workflow commands - Make `--schema` flag optional (override only, metadata takes precedence) - Add `--schema` option to `openspec new change` command **Not affected**: Legacy commands (`openspec validate`, `openspec archive`, `openspec list`, `openspec show`) ## Capabilities ### New Capabilities - `change-metadata`: Reading/writing per-change metadata files ### Modified Capabilities - `cli-artifact-workflow`: Commands auto-detect schema from change metadata ## Impact - **Affected code**: `src/utils/change-utils.ts`, `src/core/artifact-graph/instruction-loader.ts`, `src/commands/artifact-workflow.ts` - **Agent skills**: Can be simplified - no longer need to pass schema explicitly - **Backward compatible**: Changes without `.openspec.yaml` fall back to `spec-driven` default - **Isolation**: All changes contained within experimental workflow code; legacy commands untouched ================================================ FILE: openspec/changes/archive/2026-01-06-add-per-change-schema-metadata/specs/cli-artifact-workflow/spec.md ================================================ ## ADDED Requirements ### Requirement: Change Metadata The system SHALL store and validate per-change metadata in `.openspec.yaml` files using a Zod schema. #### Scenario: Metadata file created with new change - **WHEN** user runs `openspec new change add-feature --schema tdd` - **THEN** the system creates `.openspec.yaml` in the change directory - **AND** the file contains `schema: tdd` and `created: ` #### Scenario: Metadata validated on read - **WHEN** the system reads `.openspec.yaml` - **AND** the `schema` field references an unknown schema - **THEN** the system displays a validation error listing available schemas #### Scenario: Metadata schema validation - **WHEN** `.openspec.yaml` contains invalid YAML or missing required fields - **THEN** the system displays a Zod validation error with details #### Scenario: Missing metadata file - **WHEN** a change directory has no `.openspec.yaml` file - **THEN** the system falls back to the default schema (`spec-driven`) ## MODIFIED Requirements ### Requirement: New Change Command The system SHALL create new change directories with validation and optional schema metadata. #### Scenario: Create valid change - **WHEN** user runs `openspec new change add-feature` - **THEN** the system creates `openspec/changes/add-feature/` directory - **AND** creates `.openspec.yaml` with `schema: spec-driven` (default) #### Scenario: Create change with schema - **WHEN** user runs `openspec new change add-feature --schema tdd` - **THEN** the system creates `openspec/changes/add-feature/` directory - **AND** creates `.openspec.yaml` with `schema: tdd` #### Scenario: Invalid schema on create - **WHEN** user runs `openspec new change add-feature --schema unknown` - **THEN** the system displays an error listing available schemas - **AND** does not create the change directory #### Scenario: Invalid change name - **WHEN** user runs `openspec new change "Add Feature"` with invalid name - **THEN** the system displays validation error with guidance #### Scenario: Duplicate change name - **WHEN** user runs `openspec new change existing-change` for an existing change - **THEN** the system displays an error indicating the change already exists #### Scenario: Create with description - **WHEN** user runs `openspec new change add-feature --description "Add new feature"` - **THEN** the system creates the change directory with description in README.md ### Requirement: Schema Selection The system SHALL support custom schema selection for workflow commands, with automatic detection from change metadata. #### Scenario: Schema auto-detected from metadata - **WHEN** user runs `openspec status --change ` without `--schema` - **AND** the change has `.openspec.yaml` with `schema: tdd` - **THEN** the system uses the `tdd` schema #### Scenario: Explicit schema overrides metadata - **WHEN** user runs `openspec status --change --schema spec-driven` - **AND** the change has `.openspec.yaml` with `schema: tdd` - **THEN** the system uses `spec-driven` (explicit flag wins) #### Scenario: Default schema fallback - **WHEN** user runs workflow commands without `--schema` - **AND** the change has no `.openspec.yaml` file - **THEN** the system uses the "spec-driven" schema #### Scenario: Custom schema via flag - **WHEN** user runs `openspec status --change --schema tdd` - **THEN** the system uses the specified schema for artifact graph #### Scenario: Unknown schema - **WHEN** user specifies an unknown schema - **THEN** the system displays an error listing available schemas ================================================ FILE: openspec/changes/archive/2026-01-06-add-per-change-schema-metadata/tasks.md ================================================ ## 1. Zod Schema and Types - [x] 1.1 Add `ChangeMetadataSchema` Zod schema to `src/core/artifact-graph/types.ts` - [x] 1.2 Export `ChangeMetadata` type inferred from schema ## 2. Core Metadata Functions - [x] 2.1 Create `src/utils/change-metadata.ts` with `writeChangeMetadata()` function - [x] 2.2 Add `readChangeMetadata()` function with Zod validation - [x] 2.3 Update `createChange()` to accept optional `schema` param and write metadata ## 3. Auto-Detection in Instruction Loader - [x] 3.1 Modify `loadChangeContext()` to read schema from `.openspec.yaml` - [x] 3.2 Make `schemaName` parameter optional (fall back to metadata, then default) ## 4. CLI Updates - [x] 4.1 Add `--schema ` option to `openspec new change` command - [x] 4.2 Verify existing commands (`status`, `instructions`) work with auto-detection ## 5. Tests - [x] 5.1 Test `ChangeMetadataSchema` validates correctly (valid/invalid cases) - [x] 5.2 Test `writeChangeMetadata()` creates valid YAML - [x] 5.3 Test `readChangeMetadata()` parses and validates schema - [x] 5.4 Test `loadChangeContext()` auto-detects schema from metadata - [x] 5.5 Test fallback to default when no metadata exists - [x] 5.6 Test `--schema` flag overrides metadata ================================================ FILE: openspec/changes/archive/2026-01-06-add-specs-apply-command/.openspec.yaml ================================================ schema: spec-driven created: 2026-01-06 ================================================ FILE: openspec/changes/archive/2026-01-06-add-specs-apply-command/design.md ================================================ ## Context Currently, delta specs are only applied to main specs when running `openspec archive`. This bundles two concerns: 1. Applying spec changes (delta → main) 2. Archiving the change (move to archive folder) Users want flexibility to sync specs earlier, especially when iterating. The archive command already contains the reconciliation logic in `buildUpdatedSpec()`. ## Goals / Non-Goals **Goals:** - Decouple spec syncing from archiving - Provide `/opsx:sync` skill for agents to sync specs on demand - Keep operation idempotent (safe to run multiple times) **Non-Goals:** - Tracking whether specs have been synced (no state) - Changing archive behavior (it will continue to apply specs) - Supporting partial application (all deltas sync together) ## Decisions ### 1. Reuse existing reconciliation logic **Decision**: Extract `buildUpdatedSpec()` logic from `ArchiveCommand` into a shared module. **Rationale**: The archive command already implements delta parsing and application. Rather than duplicate, we extract and reuse. **Alternatives considered**: - Duplicate logic in new command (rejected: maintenance burden) - Have sync call archive with flags (rejected: coupling) ### 2. No state tracking **Decision**: Don't track whether specs have been synced. Each invocation reads delta and main specs, reconciles. **Rationale**: - Idempotent operations don't need state - Avoids sync issues between flag and reality - Simpler implementation and mental model **Alternatives considered**: - Track `specsSynced: true` in `.openspec.yaml` (rejected: unnecessary complexity) - Store snapshot of synced deltas (rejected: over-engineering) ### 3. Agent-driven approach (no CLI command) **Decision**: The `/opsx:sync` skill is fully agent-driven - the agent reads delta specs and directly edits main specs. **Rationale**: - Allows intelligent merging (add scenarios without copying entire requirements) - Delta represents *intent*, not wholesale replacement - More flexible and natural editing workflow - Archive still uses programmatic merge (for finalized changes) ### 4. Archive behavior unchanged **Decision**: Archive continues to apply specs as part of its flow. If specs are already reconciled, the operation is a no-op. **Rationale**: Backward compatibility. Users who don't use `/opsx:sync` get the same experience. ## Risks / Trade-offs **[Risk] Multiple changes modify same spec** → Last to sync wins. Same as today with archive. Users should coordinate or use sequential archives. **[Risk] User syncs specs then continues editing deltas** → Running `/opsx:sync` again reconciles. Idempotent design handles this. **[Trade-off] No undo mechanism** → Users can `git checkout` main specs if needed. Explicit undo command is out of scope. ## Implementation Approach 1. Extract spec application logic from `ArchiveCommand.buildUpdatedSpec()` into `src/core/specs-apply.ts` 2. Add skill template for `/opsx:sync` in `skill-templates.ts` 3. Register skill in managed skills ================================================ FILE: openspec/changes/archive/2026-01-06-add-specs-apply-command/proposal.md ================================================ ## Why Spec application is currently bundled with archive - users must run `openspec archive` to apply delta specs to main specs. This couples two distinct concerns (applying specs vs. archiving the change) and forces users to wait until they're "done" to see main specs updated. Users want the flexibility to sync specs earlier in the workflow while iterating. ## What Changes - Add `/opsx:sync` skill that syncs delta specs to main specs as a standalone action - The operation is idempotent - safe to run multiple times, agent reconciles main specs to match deltas - Archive continues to work as today (applies specs if not already reconciled, then moves to archive) - No new state tracking - the agent reads delta and main specs, reconciles on each run - Agent-driven approach allows intelligent merging (partial updates, adding scenarios) **Workflow becomes:** ``` /opsx:new → /opsx:continue → /opsx:apply → archive │ └── /opsx:sync (optional, anytime) ``` ## Capabilities ### New Capabilities - `specs-sync-skill`: Skill template for `/opsx:sync` command that reconciles main specs with delta specs ### Modified Capabilities - None (agent-driven, no CLI command needed) ## Impact - **Skills**: New `openspec-sync-specs` skill in `skill-templates.ts` - **Archive**: No changes needed - already does reconciliation, will continue to work - **Agent workflow**: Users gain flexibility to sync specs before archive ================================================ FILE: openspec/changes/archive/2026-01-06-add-specs-apply-command/specs/specs-sync-skill/spec.md ================================================ ## ADDED Requirements ### Requirement: Specs Sync Skill The system SHALL provide an `/opsx:sync` skill that syncs delta specs from a change to the main specs. #### Scenario: Sync delta specs to main specs - **WHEN** agent executes `/opsx:sync` with a change name - **THEN** the agent reads delta specs from `openspec/changes//specs/` - **AND** reads corresponding main specs from `openspec/specs/` - **AND** reconciles main specs to match what the deltas describe #### Scenario: Idempotent operation - **WHEN** agent executes `/opsx:sync` multiple times on the same change - **THEN** the result is the same as running it once - **AND** no duplicate requirements are created #### Scenario: Change selection prompt - **WHEN** agent executes `/opsx:sync` without specifying a change - **THEN** the agent prompts user to select from available changes - **AND** shows changes that have delta specs ### Requirement: Delta Reconciliation Logic The agent SHALL reconcile main specs with delta specs using the delta operation headers. #### Scenario: ADDED requirements - **WHEN** delta contains `## ADDED Requirements` with a requirement - **AND** the requirement does not exist in main spec - **THEN** add the requirement to main spec #### Scenario: ADDED requirement already exists - **WHEN** delta contains `## ADDED Requirements` with a requirement - **AND** a requirement with the same name already exists in main spec - **THEN** update the existing requirement to match the delta version #### Scenario: MODIFIED requirements - **WHEN** delta contains `## MODIFIED Requirements` with a requirement - **AND** the requirement exists in main spec - **THEN** replace the requirement in main spec with the delta version #### Scenario: REMOVED requirements - **WHEN** delta contains `## REMOVED Requirements` with a requirement name - **AND** the requirement exists in main spec - **THEN** remove the requirement from main spec #### Scenario: RENAMED requirements - **WHEN** delta contains `## RENAMED Requirements` with FROM:/TO: format - **AND** the FROM requirement exists in main spec - **THEN** rename the requirement to the TO name #### Scenario: New capability spec - **WHEN** delta spec exists for a capability not in main specs - **THEN** create new main spec file at `openspec/specs//spec.md` ### Requirement: Skill Output The skill SHALL provide clear feedback on what was synced. #### Scenario: Show synced changes - **WHEN** reconciliation completes successfully - **THEN** display summary of changes per capability: - Number of requirements added - Number of requirements modified - Number of requirements removed - Number of requirements renamed #### Scenario: No changes needed - **WHEN** main specs already match delta specs - **THEN** display "Specs already in sync - no changes needed" ================================================ FILE: openspec/changes/archive/2026-01-06-add-specs-apply-command/tasks.md ================================================ ## Tasks ### Core Implementation - [x] Extract spec application logic from `ArchiveCommand` into `src/core/specs-apply.ts` - Move `buildUpdatedSpec()`, `findSpecUpdates()`, `writeUpdatedSpec()` to shared module - Keep `ArchiveCommand` importing from the new module - Ensure all validation logic is preserved ### Skill Template - [x] Add `getSyncSpecsSkillTemplate()` function in `src/core/templates/skill-templates.ts` - Skill name: `openspec-sync-specs` - Description: Sync delta specs to main specs - **Agent-driven**: Instructions for agent to read deltas and edit main specs directly - [x] Add `/opsx:sync` slash command template in `skill-templates.ts` - Mirror the skill template for slash command format - **Agent-driven**: No CLI command, agent does the merge ### Registration - [x] Register skill in managed skills (via `artifact-experimental-setup`) - Add to skill list with appropriate metadata - Ensure it appears in setup output ### Design Decision **Why agent-driven instead of CLI-driven?** The programmatic merge operates at requirement-level granularity: - MODIFIED requires copying ALL scenarios, not just the changed ones - If agent forgets a scenario, it gets deleted - Delta specs become bloated with copied content Agent-driven approach: - Agent can apply partial updates (add a scenario without copying others) - Delta represents *intent*, not wholesale replacement - More flexible and natural editing workflow - Archive still uses programmatic merge (for finalized changes) ================================================ FILE: openspec/changes/archive/2026-01-06-make-apply-instructions-schema-aware/proposal.md ================================================ ## Why The `generateApplyInstructions` function is hardcoded to check for `spec-driven` artifacts (`proposal.md`, `specs/`, `design.md`, `tasks.md`). If a user selects a different schema like `tdd`, the apply instructions are meaningless - they check for files that don't exist in that schema. This blocks the experimental workflow from supporting multiple schemas properly. ## What Changes **Scope: Experimental artifact workflow** (`openspec instructions apply`) **Depends on:** `add-per-change-schema-metadata` (to know which schema a change uses) - Make `generateApplyInstructions` read artifact definitions from the schema - Dynamically determine which artifacts exist based on schema - Define when a change becomes "implementable" (see Design Decision below) - Generate schema-appropriate context files and instructions ## Design Decision: When is a change implementable? This is the key question. Different approaches: ### Option A: Explicit `apply` artifact in schema Add a field to mark which artifact is the "implementation gate": ```yaml artifacts: - id: tasks generates: tasks.md apply: true # ← This artifact triggers apply mode ``` **Pros:** Explicit, flexible **Cons:** Another field to maintain, what if multiple artifacts are `apply: true`? ### Option B: Leaf artifacts are implementable The artifact(s) with no dependents (nothing depends on them) are the apply target. - `spec-driven`: `tasks` is a leaf → apply = execute tasks - `tdd`: `docs` is a leaf → but that doesn't make sense for TDD... **Pros:** No extra schema field, derived from graph **Cons:** Doesn't match TDD semantics (implementation is the action, not docs) ### Option C: Schema-level `apply_phase` definition Add a top-level field to the schema: ```yaml name: spec-driven apply_phase: requires: [tasks] # Must exist before apply tracks: tasks.md # File with checkboxes to track instruction: "Work through tasks, mark complete as you go" ``` ```yaml name: tdd apply_phase: requires: [tests] # Must have tests before implementing tracks: null # No checkbox tracking - just make tests pass instruction: "Run tests, implement until green, refactor" ``` **Pros:** Full flexibility, schema controls its own apply semantics **Cons:** More complex schema format ### Option D: Convention-based (artifact ID matching) If artifact ID is `tasks` or `implementation`, it's the apply target. **Pros:** Simple, no schema changes **Cons:** Brittle, doesn't work for custom schemas ### Option E: All artifacts complete → apply available Apply becomes available when ALL schema artifacts exist. Implementation is whatever the user does after planning. **Pros:** Simple, no schema changes **Cons:** Doesn't guide what "apply" means for different workflows --- ## Decision: Add `apply` block to schema.yaml Add a top-level `apply` field to schema definitions: ```yaml name: spec-driven version: 1 description: Default OpenSpec workflow artifacts: # ... existing artifacts ... apply: requires: [tasks] # Artifacts that must exist before apply tracks: tasks.md # File with checkboxes for progress (optional) instruction: | # Guidance shown to agent Read context files, work through pending tasks, mark complete as you go. Pause if you hit blockers or need clarification. ``` ```yaml name: tdd version: 1 description: Test-driven development workflow artifacts: # ... existing artifacts ... apply: requires: [tests] # Must have tests before implementing tracks: null # No checkbox tracking instruction: | Run tests to see failures. Implement minimal code to pass each test. Refactor while keeping tests green. ``` **Key properties:** - `requires`: Array of artifact IDs that must exist before apply is available - `tracks`: Path to file with checkboxes (relative to change dir), or `null` if no tracking - `instruction`: Custom guidance for the apply phase **Fallback behavior:** Schemas without `apply` block default to "all artifacts must exist" ## Capabilities ### Modified Capabilities - `cli-artifact-workflow`: Apply instructions become schema-aware ## Impact - **Affected code**: `src/commands/artifact-workflow.ts` (generateApplyInstructions) - **Schema format**: May need new `apply_phase` field - **Existing schemas**: Need to add apply_phase to `spec-driven` and `tdd` - **Backward compatible**: Schemas without apply_phase can use default behavior ================================================ FILE: openspec/changes/archive/2026-01-06-make-apply-instructions-schema-aware/specs/cli-artifact-workflow/spec.md ================================================ ## ADDED Requirements ### Requirement: Schema Apply Block The system SHALL support an `apply` block in schema definitions that controls when and how implementation begins. #### Scenario: Schema with apply block - **WHEN** a schema defines an `apply` block - **THEN** the system uses `apply.requires` to determine which artifacts must exist before apply - **AND** uses `apply.tracks` to identify the file for progress tracking (or null if none) - **AND** uses `apply.instruction` for guidance shown to the agent #### Scenario: Schema without apply block - **WHEN** a schema has no `apply` block - **THEN** the system requires all artifacts to exist before apply is available - **AND** uses default instruction: "All artifacts complete. Proceed with implementation." ### Requirement: Apply Instructions Command The system SHALL generate schema-aware apply instructions via `openspec instructions apply`. #### Scenario: Generate apply instructions - **WHEN** user runs `openspec instructions apply --change ` - **AND** all required artifacts (per schema's `apply.requires`) exist - **THEN** the system outputs: - Context files from all existing artifacts - Schema-specific instruction text - Progress tracking file path (if `apply.tracks` is set) #### Scenario: Apply blocked by missing artifacts - **WHEN** user runs `openspec instructions apply --change ` - **AND** required artifacts are missing - **THEN** the system indicates apply is blocked - **AND** lists which artifacts must be created first #### Scenario: Apply instructions JSON output - **WHEN** user runs `openspec instructions apply --change --json` - **THEN** the system outputs JSON with: - `contextFiles`: array of paths to existing artifacts - `instruction`: the apply instruction text - `tracks`: path to progress file or null - `applyRequires`: list of required artifact IDs ## MODIFIED Requirements ### Requirement: Status Command The system SHALL display artifact completion status for a change, including apply readiness. #### Scenario: Status JSON includes apply requirements - **WHEN** user runs `openspec status --change --json` - **THEN** the system outputs JSON with: - `changeName`, `schemaName`, `isComplete`, `artifacts` array - `applyRequires`: array of artifact IDs needed for apply phase ================================================ FILE: openspec/changes/archive/2026-01-06-make-apply-instructions-schema-aware/tasks.md ================================================ ## Prerequisites - [x] 0.1 Implement `add-per-change-schema-metadata` first (to auto-detect schema) ## 1. Schema Format - [x] 1.1 Add `ApplyPhaseSchema` Zod schema to `src/core/artifact-graph/types.ts` - [x] 1.2 Update `SchemaYamlSchema` to include optional `apply` field - [x] 1.3 Export `ApplyPhase` type ## 2. Update Existing Schemas - [x] 2.1 Add `apply` block to `schemas/spec-driven/schema.yaml` - [x] 2.2 Add `apply` block to `schemas/tdd/schema.yaml` ## 3. Refactor generateApplyInstructions - [x] 3.1 Load schema via `resolveSchema(schemaName)` - [x] 3.2 Read `apply.requires` to determine required artifacts - [x] 3.3 Check artifact existence dynamically (not hardcoded paths) - [x] 3.4 Use `apply.tracks` for progress tracking (or skip if null) - [x] 3.5 Use `apply.instruction` for the instruction text - [x] 3.6 Build `contextFiles` from all existing artifacts in schema ## 4. Handle Fallback - [x] 4.1 If schema has no `apply` block, require all artifacts to exist - [x] 4.2 Default instruction: "All artifacts complete. Proceed with implementation." ## 5. Tests - [x] 5.1 Test apply instructions with spec-driven schema - [x] 5.2 Test apply instructions with tdd schema - [x] 5.3 Test fallback when schema has no apply block - [x] 5.4 Test blocked state when required artifacts missing ================================================ FILE: openspec/changes/archive/2026-01-06-opsx-archive-command/.openspec.yaml ================================================ schema: spec-driven created: 2026-01-07 ================================================ FILE: openspec/changes/archive/2026-01-06-opsx-archive-command/design.md ================================================ ## Context The experimental workflow (OPSX) provides a complete lifecycle for creating changes: - `/opsx:new` - Scaffold a new change with schema - `/opsx:continue` - Create next artifact - `/opsx:ff` - Fast-forward all artifacts - `/opsx:apply` - Implement tasks - `/opsx:sync` - Sync delta specs to main The missing piece is archiving. The existing `openspec archive` command works but: 1. Applies specs programmatically (not agent-driven) 2. Doesn't use the artifact graph for completion checking 3. Doesn't integrate with the OPSX workflow philosophy ## Goals / Non-Goals **Goals:** - Add `/opsx:archive` skill to complete the OPSX workflow lifecycle - Use artifact graph for schema-aware completion checking - Integrate with `/opsx:sync` for agent-driven spec syncing - Preserve `.openspec.yaml` schema metadata in archive **Non-Goals:** - Replacing the existing `openspec archive` CLI command - Changing how specs are applied in the CLI command - Modifying the artifact graph or schema system ## Decisions ### Decision 1: Skill-only implementation (no new CLI command) The `/opsx:archive` will be a slash command/skill only, not a new CLI command. **Rationale**: The existing `openspec archive` CLI command already handles the core archive functionality (moving to archive folder, date prefixing). The OPSX version just needs different pre-archive checks and optional sync prompting, which are agent behaviors better suited to a skill. **Alternatives considered**: - Adding flags to `openspec archive` (e.g., `--experimental`) - Rejected: adds complexity to CLI, harder to maintain two code paths - New CLI command `openspec archive-experimental` - Rejected: unnecessary duplication, agent skills are the OPSX pattern ### Decision 2: Prompt for sync before archive The skill will check for unsynced delta specs and prompt the user before archiving. **Rationale**: The OPSX philosophy is agent-driven intelligent merging via `/opsx:sync`. Rather than programmatically applying specs like the regular archive command, we prompt the user to sync first if needed. This maintains workflow flexibility (user can decline and just archive). **Flow**: 1. Check if `specs/` directory exists in the change 2. If yes, ask: "This change has delta specs. Would you like to sync them to main specs before archiving?" 3. If user says yes, execute `/opsx:sync` logic 4. Proceed with archive regardless of answer ### Decision 3: Use artifact graph for completion checking The skill will use `openspec status --change "" --json` to check artifact completion instead of just validating proposal.md and specs. **Rationale**: The experimental workflow is schema-aware. Different schemas have different required artifacts. The artifact graph knows which artifacts are complete/incomplete for the current schema. **Behavior**: - Show warning if any artifacts are not `done` - Don't block archive (user may have valid reasons to archive early) - List incomplete artifacts so user can make informed decision ### Decision 4: Reuse tasks.md completion check from regular archive The skill will parse tasks.md and warn about incomplete tasks, same as regular archive. **Rationale**: Task completion checking is valuable regardless of workflow. The logic is simple (count `- [ ]` vs `- [x]`) and doesn't need special OPSX handling. ### Decision 5: Move change to archive/ with date prefix Same archive behavior as regular command: move to `openspec/changes/archive/YYYY-MM-DD-/`. **Rationale**: Consistency with existing archive convention. The `.openspec.yaml` file moves with the change, preserving schema metadata. ## Risks / Trade-offs **Risk**: Users confused about when to use `/opsx:archive` vs `openspec archive` → **Mitigation**: Documentation should clarify: use `/opsx:archive` if you've been using the OPSX workflow, use `openspec archive` otherwise. Both produce the same archived result. **Risk**: Incomplete sync if user declines and has delta specs → **Mitigation**: The prompt is informational; user has full control. They may want to archive without syncing (e.g., abandoned change). Log a note in output. **Trade-off**: No programmatic spec application in OPSX archive → **Accepted**: This is intentional. OPSX philosophy is agent-driven merging. If user wants programmatic application, use `openspec archive` instead. ================================================ FILE: openspec/changes/archive/2026-01-06-opsx-archive-command/proposal.md ================================================ ## Why The experimental workflow (OPSX) provides a schema-driven, artifact-by-artifact approach to creating changes with `/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:apply`, and `/opsx:sync`. However, there's no corresponding archive command to finalize and archive completed changes. Users must currently fall back to the regular `openspec archive` command, which doesn't integrate with the OPSX philosophy of agent-driven spec syncing and schema-aware artifact tracking. ## What Changes - Add `/opsx:archive` slash command for archiving changes in the experimental workflow - Use artifact graph to check completion status (schema-aware) instead of just validating proposal + specs - Prompt for `/opsx:sync` before archiving instead of programmatically applying specs - Preserve `.openspec.yaml` schema metadata when moving to archive - Integrate with existing OPSX commands for a cohesive workflow ## Capabilities ### New Capabilities - `opsx-archive-skill`: Slash command and skill for archiving completed changes in the experimental workflow. Checks artifact completion via artifact graph, verifies task completion, optionally syncs specs via `/opsx:sync`, and moves the change to `archive/YYYY-MM-DD-/`. ### Modified Capabilities (none - this is a new skill that doesn't modify existing specs) ## Impact - New file: `.claude/commands/opsx/archive.md` - New skill definition (generated via `openspec artifact-experimental-setup`) - No changes to existing archive command or other OPSX commands - Completes the OPSX command suite for full lifecycle management ================================================ FILE: openspec/changes/archive/2026-01-06-opsx-archive-command/specs/opsx-archive-skill/spec.md ================================================ ## ADDED Requirements ### Requirement: OPSX Archive Skill The system SHALL provide an `/opsx:archive` skill that archives completed changes in the experimental workflow. #### Scenario: Archive a change with all artifacts complete - **WHEN** agent executes `/opsx:archive` with a change name - **AND** all artifacts in the schema are complete - **AND** all tasks are complete - **THEN** the agent moves the change to `openspec/changes/archive/YYYY-MM-DD-/` - **AND** displays success message with archived location #### Scenario: Change selection prompt - **WHEN** agent executes `/opsx:archive` without specifying a change - **THEN** the agent prompts user to select from available changes - **AND** shows only active changes (excludes archive/) ### Requirement: Artifact Completion Check The skill SHALL check artifact completion status using the artifact graph before archiving. #### Scenario: Incomplete artifacts warning - **WHEN** agent checks artifact status - **AND** one or more artifacts have status other than `done` - **THEN** display warning listing incomplete artifacts - **AND** prompt user for confirmation to continue - **AND** proceed if user confirms #### Scenario: All artifacts complete - **WHEN** agent checks artifact status - **AND** all artifacts have status `done` - **THEN** proceed without warning ### Requirement: Task Completion Check The skill SHALL check task completion status from tasks.md before archiving. #### Scenario: Incomplete tasks found - **WHEN** agent reads tasks.md - **AND** incomplete tasks are found (marked with `- [ ]`) - **THEN** display warning showing count of incomplete tasks - **AND** prompt user for confirmation to continue - **AND** proceed if user confirms #### Scenario: All tasks complete - **WHEN** agent reads tasks.md - **AND** all tasks are complete (marked with `- [x]`) - **THEN** proceed without task-related warning #### Scenario: No tasks file - **WHEN** tasks.md does not exist - **THEN** proceed without task-related warning ### Requirement: Spec Sync Prompt The skill SHALL prompt to sync delta specs before archiving if specs exist. #### Scenario: Delta specs exist - **WHEN** agent checks for delta specs - **AND** `specs/` directory exists in the change with spec files - **THEN** prompt user: "This change has delta specs. Would you like to sync them to main specs before archiving?" - **AND** if user confirms, execute `/opsx:sync` logic - **AND** proceed with archive regardless of sync choice #### Scenario: No delta specs - **WHEN** agent checks for delta specs - **AND** no `specs/` directory or no spec files exist - **THEN** proceed without sync prompt ### Requirement: Archive Process The skill SHALL move the change to the archive folder with date prefix. #### Scenario: Successful archive - **WHEN** archiving a change - **THEN** create `archive/` directory if it doesn't exist - **AND** generate target name as `YYYY-MM-DD-` using current date - **AND** move entire change directory to archive location - **AND** preserve `.openspec.yaml` file in archived change #### Scenario: Archive already exists - **WHEN** target archive directory already exists - **THEN** fail with error message - **AND** suggest renaming existing archive or using different date ### Requirement: Skill Output The skill SHALL provide clear feedback about the archive operation. #### Scenario: Archive complete with sync - **WHEN** archive completes after syncing specs - **THEN** display summary: - Specs synced (from `/opsx:sync` output) - Change archived to location - Schema that was used #### Scenario: Archive complete without sync - **WHEN** archive completes without syncing specs - **THEN** display summary: - Note that specs were not synced (if applicable) - Change archived to location - Schema that was used #### Scenario: Archive complete with warnings - **WHEN** archive completes with incomplete artifacts or tasks - **THEN** include note about what was incomplete - **AND** suggest reviewing if archive was intentional ================================================ FILE: openspec/changes/archive/2026-01-06-opsx-archive-command/tasks.md ================================================ ## 1. Create Slash Command - [x] 1.1 Create `.claude/commands/opsx/archive.md` with skill definition - [x] 1.2 Add YAML frontmatter (name, description, category, tags) - [x] 1.3 Implement change selection logic (prompt if not provided) - [x] 1.4 Implement artifact completion check using `openspec status --json` - [x] 1.5 Implement task completion check (parse tasks.md for `- [ ]`) - [x] 1.6 Implement spec sync prompt (check for specs/ directory, offer `/opsx:sync`) - [x] 1.7 Implement archive process (move to archive/YYYY-MM-DD-/) - [x] 1.8 Add output formatting for success/warning cases ## 2. Regenerate Skills - [x] 2.1 Run `openspec artifact-experimental-setup` to regenerate skills - [x] 2.2 Verify skill appears in `.claude/skills/` directory ## 3. Testing - [x] 3.1 Test `/opsx:archive` with a complete change (all artifacts, all tasks done) - [x] 3.2 Test `/opsx:archive` with incomplete artifacts (verify warning shown) - [x] 3.3 Test `/opsx:archive` with incomplete tasks (verify warning shown) - [x] 3.4 Test `/opsx:archive` with delta specs (verify sync prompt shown) - [x] 3.5 Test `/opsx:archive` without change name (verify selection prompt) ================================================ FILE: openspec/changes/archive/2026-01-07-add-nix-flake-support/.openspec.yaml ================================================ schema: spec-driven created: 2026-01-07 ================================================ FILE: openspec/changes/archive/2026-01-07-add-nix-flake-support/design.md ================================================ ## Context OpenSpec is a TypeScript CLI tool using pnpm for dependency management. The project requires Node.js ≥20.19.0. Nix uses its own build system that needs to understand how to fetch dependencies and build the project reproducibly. The Nix ecosystem has specific patterns for packaging Node.js/pnpm projects that differ from the traditional npm ecosystem. ## Goals - Enable OpenSpec to be run directly via `nix run github:Fission-AI/OpenSpec` - Support all major platforms (Linux x86/ARM, macOS x86/ARM) - Use existing pnpm-lock.yaml for reproducible builds - Provide development environment for Nix users ## Non-Goals - Replace existing npm/pnpm publishing workflow - Publish to nixpkgs (can be done later as separate effort) - Support Windows (Nix doesn't run natively on Windows) ## Decisions ### Use stdenv.mkDerivation instead of buildNpmPackage **Decision**: Package OpenSpec using `stdenv.mkDerivation` with pnpm hooks. **Rationale**: The zigbee2mqtt package in nixpkgs demonstrates the current best practice for pnpm projects. Using `buildNpmPackage` with pnpm requires complex configuration, while `mkDerivation` with the right hooks is more straightforward and better supported. **Alternative considered**: Using `buildNpmPackage` with `npmConfigHook = pkgs.pnpmConfigHook` - this is the older pattern and causes issues with dependency fetching. ### Use fetchPnpmDeps with explicit pnpm version **Decision**: Use `pkgs.fetchPnpmDeps` with `pnpm = pkgs.pnpm_9` and `fetcherVersion = 3`. **Rationale**: - pnpm lockfile version 9.0 requires fetcherVersion 3 - Explicit pnpm_9 ensures consistency between fetch and build - This is the documented way to handle pnpm projects in nixpkgs ### Multi-platform support without flake-utils **Decision**: Implement multi-platform support using plain Nix with `nixpkgs.lib.genAttrs`. **Rationale**: Per user request, avoid extra dependencies. The `genAttrs` pattern is simple and well-understood in the Nix community. ### Node.js 20 instead of latest **Decision**: Pin to nodejs_20 to match package.json engines requirement. **Rationale**: Ensures consistency with development environment and npm package requirements. Avoids potential compatibility issues with newer Node versions. ## Key Implementation Details ### Dependency Hash Management The `pnpmDeps.hash` field must be updated whenever dependencies change. The workflow: 1. Set hash to fake value (all zeros) 2. Run `nix build` 3. Nix fails with actual hash 4. Update flake.nix with correct hash This is standard Nix workflow for fixed-output derivations. ### Build Inputs Required nativeBuildInputs: - `nodejs_20` - runtime - `npmHooks.npmInstallHook` - handles installation phase - `pnpmConfigHook` - configures pnpm environment - `pnpm_9` - pnpm executable The `dontNpmPrune = true` is important to keep all dependencies after build. ## Risks / Trade-offs **[Risk]** Hash needs updating when dependencies change → **Mitigation**: Document this clearly; error message from Nix provides correct hash **[Risk]** Nix builds might lag behind npm releases → **Mitigation**: This is fine; Nix users can still use npm if they need bleeding edge **[Trade-off]** Additional maintenance burden for hash updates → **Benefit**: Better experience for Nix ecosystem users ## Migration Plan 1. Add flake.nix to repository 2. Test builds on multiple platforms (can use GitHub Actions with Nix) 3. Update README with Nix installation instructions 4. Optionally add to CI pipeline to catch hash mismatches early No breaking changes - this is purely additive. ## Open Questions - Should we add automatic hash updating to CI? (Could use nix-update-script) - Should we submit to nixpkgs after validation? (Separate decision) - Do we want to support older Node versions in flake? (Probably no - stick to package.json requirement) ================================================ FILE: openspec/changes/archive/2026-01-07-add-nix-flake-support/proposal.md ================================================ ## Why OpenSpec users on NixOS or using the Nix package manager cannot easily install or run OpenSpec without going through npm. Adding a Nix flake makes OpenSpec a first-class citizen in the Nix ecosystem, enabling users to run `nix run github:Fission-AI/OpenSpec -- init` or include OpenSpec in their development environments declaratively. ## What Changes - Add `flake.nix` to repository root with multi-platform support (x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin) - Package uses pnpm for dependency management (matching existing development workflow) - Support both direct execution via `nix run` and installation via `nix profile install` - Provide dev shell for contributors using Nix ## Capabilities ### New Capabilities - `nix-flake-support`: Nix flake configuration for building and running OpenSpec ### Modified Capabilities - None ## Impact - **New files**: `flake.nix` in repository root - **Documentation**: Should add installation instructions for Nix users - **CI/CD**: Could add flake checking to CI pipeline (optional) - **Maintenance**: Requires updating pnpmDeps hash when dependencies change ================================================ FILE: openspec/changes/archive/2026-01-07-add-nix-flake-support/specs/nix-flake-support/spec.md ================================================ ## ADDED Requirements ### Requirement: Multi-platform Nix flake The system SHALL provide a Nix flake that builds OpenSpec for multiple platforms. #### Scenario: Build on Linux x86_64 - **WHEN** user runs `nix build` on x86_64-linux system - **THEN** system builds OpenSpec package successfully - **AND** package includes the `openspec` binary #### Scenario: Build on macOS ARM - **WHEN** user runs `nix build` on aarch64-darwin system - **THEN** system builds OpenSpec package successfully - **AND** package includes the `openspec` binary #### Scenario: Build on Linux ARM - **WHEN** user runs `nix build` on aarch64-linux system - **THEN** system builds OpenSpec package successfully #### Scenario: Build on macOS x86_64 - **WHEN** user runs `nix build` on x86_64-darwin system - **THEN** system builds OpenSpec package successfully ### Requirement: Direct execution via nix run The system SHALL allow users to run OpenSpec directly from GitHub without installing. #### Scenario: Run init command from GitHub - **WHEN** user runs `nix run github:Fission-AI/OpenSpec -- init` - **THEN** system downloads and builds OpenSpec - **AND** executes `openspec init` command #### Scenario: Run any OpenSpec command - **WHEN** user runs `nix run github:Fission-AI/OpenSpec -- ` - **THEN** system executes `openspec ` ### Requirement: pnpm dependency management The system SHALL use pnpm for building OpenSpec in the Nix flake. #### Scenario: Fetch dependencies with pnpm - **WHEN** Nix builds the package - **THEN** system uses `fetchPnpmDeps` to download dependencies - **AND** uses pnpm-lock.yaml for reproducible builds - **AND** uses fetcherVersion 3 for lockfile version 9.0 #### Scenario: Build with pnpm - **WHEN** Nix runs the build phase - **THEN** system executes `pnpm run build` - **AND** produces dist directory with compiled TypeScript ### Requirement: Node.js version compatibility The system SHALL use Node.js 20 as specified in package.json engines field. #### Scenario: Build with correct Node version - **WHEN** Nix builds OpenSpec - **THEN** system uses nodejs_20 from nixpkgs - **AND** build succeeds without version compatibility errors ### Requirement: Development shell The system SHALL provide a Nix development shell for contributors. #### Scenario: Enter dev shell - **WHEN** user runs `nix develop` in OpenSpec repository - **THEN** system provides shell with nodejs_20 and pnpm_9 - **AND** displays welcome message with versions - **AND** provides instructions to run `pnpm install` ### Requirement: Proper binary installation The system SHALL install the openspec binary correctly. #### Scenario: Binary in PATH - **WHEN** package is built or installed - **THEN** `openspec` binary is available in `$out/bin/openspec` - **AND** binary is executable - **AND** binary can be invoked without full path when installed #### Scenario: Binary executes correctly - **WHEN** user runs the installed `openspec` command - **THEN** system executes the CLI entry point - **AND** all subcommands work correctly ================================================ FILE: openspec/changes/archive/2026-01-07-add-nix-flake-support/tasks.md ================================================ ## 1. Create Flake Structure - [x] 1.1 Create flake.nix in repository root - [x] 1.2 Define inputs (nixpkgs only, no flake-utils) - [x] 1.3 Set up supportedSystems list (4 platforms) - [x] 1.4 Create forAllSystems helper function ## 2. Configure Package Build - [x] 2.1 Set up stdenv.mkDerivation with finalAttrs pattern - [x] 2.2 Configure pnpmDeps with fetchPnpmDeps - [x] 2.3 Set pnpm = pnpm_9 and fetcherVersion = 3 - [x] 2.4 Add placeholder hash (all zeros) - [x] 2.5 Configure nativeBuildInputs (nodejs_20, hooks, pnpm_9) - [x] 2.6 Set dontNpmPrune = true ## 3. Define Build Phase - [x] 3.1 Add buildPhase with runHook preBuild - [x] 3.2 Add pnpm run build command - [x] 3.3 Add runHook postBuild ## 4. Configure Installation - [x] 4.1 Let npmInstallHook handle installation automatically - [x] 4.2 Verify binary ends up in $out/bin/openspec ## 5. Add Metadata - [x] 5.1 Set meta.description - [x] 5.2 Set meta.homepage - [x] 5.3 Set meta.license (MIT) - [x] 5.4 Set meta.mainProgram = "openspec" ## 6. Configure App Entry Point - [x] 6.1 Add apps output with forAllSystems - [x] 6.2 Set default app to openspec binary - [x] 6.3 Test that nix run works ## 7. Add Development Shell - [x] 7.1 Add devShells output with forAllSystems - [x] 7.2 Include nodejs_20 and pnpm_9 in buildInputs - [x] 7.3 Add shellHook with welcome message and instructions ## 8. Get Correct Dependency Hash - [x] 8.1 Run nix build to trigger hash mismatch - [x] 8.2 Copy correct hash from error message - [x] 8.3 Update pnpmDeps.hash in flake.nix - [x] 8.4 Verify build succeeds ## 9. Testing - [x] 9.1 Test `nix build` on x86_64-linux - [x] 9.2 Test `nix run . -- --version` works - [x] 9.3 Test `nix develop` provides correct environment - [ ] 9.4 Test on macOS if available - [ ] 9.5 Test `nix run github:Fission-AI/OpenSpec -- init` after merge to main ## 10. Documentation - [x] 10.1 Add Nix installation section to README - [x] 10.2 Include example commands for common Nix workflows in README ================================================ FILE: openspec/changes/archive/2026-01-09-add-flake-update-script/.openspec.yaml ================================================ schema: spec-driven created: 2026-01-09 ================================================ FILE: openspec/changes/archive/2026-01-09-add-flake-update-script/design.md ================================================ ## Context The Nix flake added in the previous change requires manual maintenance when: 1. Package version changes (must update flake.nix version field) 2. Dependencies change (must update pnpmDeps hash) Currently this requires maintainers to: - Manually edit flake.nix version - Set placeholder hash - Run nix build to get error - Copy hash from error message - Update flake.nix again - Verify build works This is tedious and error-prone, especially for maintainers unfamiliar with Nix. ## Goals - Automate version and hash updates for flake.nix - Make script idempotent and safe to run multiple times - Provide clear feedback during execution - Integrate easily into release workflow ## Non-Goals - Automatically commit changes (maintainer decides when to commit) - Support non-pnpm package managers - Handle complex Nix configurations beyond OpenSpec's use case ## Decisions ### Use Bash instead of Node.js script **Decision**: Implement as bash script rather than Node.js. **Rationale**: - Needs to call Nix commands which are bash-native - Parsing Nix output is simpler in bash with grep/sed - Maintainers updating flake.nix likely have Nix installed (bash environment) - Node.js would add unnecessary complexity for shell operations **Alternative considered**: Node.js script with child_process - adds dependency on extra npm packages for shell operations, less natural for Nix tooling. ### Extract hash from build error output **Decision**: Trigger intentional build failure with placeholder hash to get correct hash. **Rationale**: This is the standard Nix workflow for updating fixed-output derivations. No API exists to compute the hash without building. **Alternative considered**: Pre-compute hash from pnpm-lock.yaml - would require understanding Nix's hash algorithm and pnpm's lockfile structure, fragile and non-standard. ### Use sed for in-place file editing **Decision**: Use `sed -i` for updating flake.nix in place. **Rationale**: Simple, available on all Unix-like systems, handles the specific replacement patterns needed. **Alternative considered**: - Using Node.js to parse/modify: Overkill for simple string replacement - Manual `sed` without `-i`: Requires temp files, more complex ### Verify build after hash update **Decision**: Always run verification build after updating hash. **Rationale**: Catches errors immediately, gives maintainer confidence the update worked. **Trade-off**: Takes extra time (~30s) but prevents broken flake.nix commits. ## Key Implementation Details ### Path Resolution Script calculates paths relative to its own location: ```bash SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" ``` This allows running from any working directory. ### Error Handling Uses `set -euo pipefail` for strict error handling: - `-e`: Exit on any command failure - `-u`: Exit on undefined variable access - `-o pipefail`: Catch failures in pipes ### Hash Extraction Pattern Uses grep with Perl regex to extract hash: ```bash grep -oP 'got:\s+\Ksha256-[A-Za-z0-9+/=]+' ``` This reliably extracts the hash regardless of surrounding text. ## Risks / Trade-offs **[Risk]** Script assumes standard Nix error message format → **Mitigation**: If extraction fails, script exits with error and shows full output **[Risk]** Build might fail for reasons other than hash mismatch → **Mitigation**: Script checks for hash in output before proceeding **[Trade-off]** Requires Nix installed to run → **Benefit**: Only maintainers updating flake need to run this, and they have Nix ## Migration Plan 1. Add script to scripts directory 2. Document in scripts/README.md 3. Use in next version bump to verify workflow 4. Update CONTRIBUTING.md if needed to mention script No breaking changes - purely additive tooling. ## Open Questions None - straightforward automation script. ================================================ FILE: openspec/changes/archive/2026-01-09-add-flake-update-script/proposal.md ================================================ ## Why Maintaining the Nix flake requires manual updates to version and dependency hash when releasing new versions or updating dependencies. This is error-prone and requires maintainers to understand Nix internals. Automating this process ensures consistency and reduces friction for releases. ## What Changes - Add `scripts/update-flake.sh` to automatically update flake.nix version and dependency hash - Add `scripts/README.md` documenting all maintenance scripts - Script extracts version from package.json and determines correct pnpm dependency hash automatically ## Capabilities ### New Capabilities - `flake-update-script`: Automation script for maintaining flake.nix ### Modified Capabilities - None ## Impact - **New files**: `scripts/update-flake.sh`, `scripts/README.md` - **Maintainer workflow**: Version bumps now include running `./scripts/update-flake.sh` - **Dependencies**: Script requires Node.js (already a dependency) and Nix (for maintainers using Nix) ================================================ FILE: openspec/changes/archive/2026-01-09-add-flake-update-script/specs/flake-update-script/spec.md ================================================ ## ADDED Requirements ### Requirement: Dynamic Version Support The script SHALL support flake.nix configurations that read version dynamically from package.json. #### Scenario: Version validation - **WHEN** script runs - **THEN** version is read from package.json using Node.js - **AND** script verifies flake.nix uses dynamic version pattern - **AND** warns if hardcoded version is detected #### Scenario: Version display - **WHEN** script runs - **THEN** script displays current package version - **AND** indicates version is read dynamically by flake.nix ### Requirement: Automatic Hash Determination The script SHALL automatically determine and update the correct pnpm dependency hash. #### Scenario: Trigger build to get hash - **WHEN** script needs to determine correct hash - **THEN** script sets placeholder hash in flake.nix - **AND** runs nix build which fails with correct hash - **AND** extracts correct hash from build error output #### Scenario: Hash extraction from build output - **WHEN** nix build fails with hash mismatch - **THEN** script parses "got: sha256-..." from error output - **AND** updates flake.nix with correct hash #### Scenario: Hash update failure - **WHEN** script cannot extract hash from build output - **THEN** script restores original hash to flake.nix - **AND** exits with error code 1 - **AND** displays build output for debugging ### Requirement: Build Verification The script SHALL verify that flake.nix builds successfully after updates. #### Scenario: Successful verification - **WHEN** hash has been updated - **THEN** script runs nix build to verify - **AND** reports success if build completes #### Scenario: Dirty git tree warning - **WHEN** build succeeds but git tree is dirty - **THEN** script reports warning about dirty tree - **AND** still indicates build success ### Requirement: User Feedback The script SHALL provide clear progress information and next steps. #### Scenario: Progress reporting - **WHEN** script runs - **THEN** each step is reported with descriptive message - **AND** detected version and hash are displayed #### Scenario: Success summary - **WHEN** script completes successfully - **THEN** summary shows version and hash changes - **AND** next steps are displayed (test, verify, commit) #### Scenario: No changes needed - **WHEN** hash is already up-to-date - **THEN** script reports no changes needed - **AND** exits with success code 0 ### Requirement: Script Safety The script SHALL fail fast on errors and use safe defaults. #### Scenario: Bash error handling - **WHEN** script encounters an error - **THEN** script exits immediately (set -e) - **AND** undefined variables cause exit (set -u) - **AND** pipe failures are caught (set -o pipefail) #### Scenario: File path resolution - **WHEN** script determines file locations - **THEN** paths are calculated relative to script location - **AND** script works regardless of working directory ### Requirement: Documentation The system SHALL provide documentation for the update script. #### Scenario: Script usage documentation - **WHEN** maintainer needs to use update script - **THEN** scripts/README.md explains when and how to use it - **AND** example workflow is provided #### Scenario: Script listing - **WHEN** maintainer views scripts/README.md - **THEN** all maintenance scripts are documented - **AND** purpose of each script is clear ================================================ FILE: openspec/changes/archive/2026-01-09-add-flake-update-script/tasks.md ================================================ ## 1. Create Update Script - [x] 1.1 Create scripts/update-flake.sh file - [x] 1.2 Add shebang and error handling (set -euo pipefail) - [x] 1.3 Add path resolution for project root and files - [x] 1.4 Make script executable (chmod +x) ## 2. Implement Version Update Logic - [x] 2.1 Extract version from package.json using Node.js - [x] 2.2 Use sed to update version in flake.nix - [x] 2.3 Report if version already up-to-date - [x] 2.4 Display detected version to user ## 3. Implement Hash Update Logic - [x] 3.1 Set placeholder hash in flake.nix - [x] 3.2 Run nix build and capture output (allow failure) - [x] 3.3 Extract correct hash from build error using grep - [x] 3.4 Handle case where hash extraction fails - [x] 3.5 Update flake.nix with correct hash - [x] 3.6 Display detected hash to user ## 4. Add Build Verification - [x] 4.1 Run nix build after hash update - [x] 4.2 Check for dirty git tree warning - [x] 4.3 Report success or failure clearly ## 5. Add User Feedback - [x] 5.1 Add progress messages for each step - [x] 5.2 Add success summary with version and hash - [x] 5.3 Add next steps instructions (test, commit) - [x] 5.4 Add error messages with context ## 6. Create Documentation - [x] 6.1 Create scripts/README.md - [x] 6.2 Document update-flake.sh purpose and usage - [x] 6.3 Add example workflow - [x] 6.4 Document other existing scripts ## 7. Testing - [x] 7.1 Test script runs successfully - [x] 7.2 Verify version is extracted correctly - [x] 7.3 Verify hash is updated correctly - [x] 7.4 Verify build succeeds after update - [x] 7.5 Test idempotency (running twice works) ## 8. Integration - [ ] 8.1 Add note to release process documentation - [ ] 8.2 Use in next actual version bump to validate workflow ================================================ FILE: openspec/changes/archive/2026-01-09-add-posthog-analytics/.openspec.yaml ================================================ schema: spec-driven created: 2026-01-10 ================================================ FILE: openspec/changes/archive/2026-01-09-add-posthog-analytics/design.md ================================================ ## Context OpenSpec needs usage analytics to understand adoption and inform product decisions. PostHog provides a privacy-conscious analytics platform suitable for open source projects. ## Goals / Non-Goals **Goals:** - Track daily/weekly/monthly active usage - Understand command usage patterns - Keep implementation minimal and privacy-respecting - Enable opt-out with minimal friction **Non-Goals:** - Detailed error tracking or diagnostics - User identification or profiling - Complex event hierarchies - Full CLI command for telemetry management (env var sufficient for now) ## Decisions ### Opt-Out Model **Decision:** Telemetry enabled by default, opt-out via environment variable. ```bash OPENSPEC_TELEMETRY=0 # Disable telemetry DO_NOT_TRACK=1 # Industry standard, also respected ``` Auto-disabled when `CI=true` is detected. **Rationale:** - Opt-in typically yields ~3% participation—not enough for meaningful data - Understanding usage patterns requires statistically significant sample sizes - Environment variable opt-out is simple and immediate - Respecting `DO_NOT_TRACK` follows industry convention **Alternatives considered:** - Opt-in only - Insufficient data for product decisions - Config file setting - More complex, env var sufficient for MVP - Full `openspec telemetry` command - Can add later if users request ### Event Design **Decision:** Single event type with minimal properties. ```typescript { event: 'command_executed', properties: { command: 'init', // Command name only version: '1.2.3' // OpenSpec version } } ``` **Rationale:** - Answers the core questions: how much usage, which commands are popular - PostHog derives DAU/WAU/MAU from anonymous user counts over time - No arguments, paths, or content—clean privacy story - Easy to explain in disclosure notice **Not tracked:** - Command arguments - File paths or contents - Error messages or stack traces - Project names or spec content - IP addresses (`$ip: null` explicitly set) ### Anonymous ID **Decision:** Random UUID, lazily generated on first telemetry send, stored in global config. ```typescript // ~/.config/openspec/config.json { "telemetry": { "anonymousId": "f47ac10b-58cc-4372-a567-0e02b2c3d479" } } ``` **Rationale:** - Random UUID has no relation to the person—can't be reversed - Stored in config so same user = same ID across sessions (needed for DAU/WAU/MAU) - Lazy generation means no ID created if user opts out before first command - User can delete config to reset identity **Alternatives considered:** - Machine-derived hash (hostname, MAC) - Feels invasive, fingerprint-like - Per-session UUID - Breaks user counting metrics entirely ### SDK Configuration **Decision:** PostHog Node SDK with immediate flush, shutdown on exit. ```typescript const posthog = new PostHog(API_KEY, { flushAt: 1, // Send immediately, don't batch flushInterval: 0 // No timer-based flushing }); // Before CLI exits await posthog.shutdown(); ``` **Rationale:** - CLI processes are short-lived; batching would lose events - `flushAt: 1` ensures each event sends immediately - `shutdown()` guarantees flush before process exit - Adds ~100-300ms to exit—negligible for typical CLI workflows **Error handling:** - Network failures silently ignored (telemetry shouldn't break CLI) - `shutdown()` wrapped in try/catch ### Hook Location **Decision:** Commander.js `preAction` and `postAction` hooks. ```typescript program .hook('preAction', (thisCommand) => { maybeShowTelemetryNotice(); trackCommand(thisCommand.name(), VERSION); }) .hook('postAction', async () => { await shutdown(); }); ``` **Rationale:** - Centralized—one place for all telemetry logic - Automatic—new commands get tracked without code changes - Clean separation—command handlers don't know about telemetry **Subcommand handling:** - Track full command path for nested commands (e.g., `change:apply`) ### First-Run Notice **Decision:** One-liner on first command ever, stored "seen" flag in config. ``` Note: OpenSpec collects anonymous usage stats. Opt out: OPENSPEC_TELEMETRY=0 ``` **Rationale:** - First command (not just `init`) ensures notice is always seen - Non-blocking—no prompt, just informational - One-liner is visible but not intrusive - Storing "seen" in config prevents repeated display **Config after first run:** ```json { "telemetry": { "anonymousId": "...", "noticeSeen": true } } ``` ## Risks / Trade-offs | Risk | Mitigation | |------|------------| | Users prefer opt-in | Clear disclosure, trivial opt-out, transparent about what's collected | | GDPR concerns | No personal data, no IP, user can delete config | | Slows CLI exit by ~200ms | Negligible for most workflows; can optimize if needed | | PostHog outage affects CLI | Fire-and-forget with timeout; failures are silent | ## Open Questions None—design is intentionally minimal. Future enhancements (dedicated command, workflow tracking) can be added based on user feedback. ================================================ FILE: openspec/changes/archive/2026-01-09-add-posthog-analytics/proposal.md ================================================ ## Why OpenSpec currently has no visibility into how the tool is being used. Without analytics, we cannot: - Understand which commands and features are most valuable to users - Measure adoption and usage patterns - Make data-driven decisions about product development Adding PostHog analytics enables product insights while respecting user privacy through transparent, opt-out telemetry. ## What Changes - Add PostHog Node.js SDK as a dependency - Implement telemetry system with environment variable opt-out - Track command usage (command name and version only) - Show first-run notice informing users about telemetry - Store anonymous ID in global config (`~/.config/openspec/config.json`) - Respect `DO_NOT_TRACK` and `OPENSPEC_TELEMETRY=0` environment variables - Auto-disable in CI environments ## Capabilities ### New Capabilities - `telemetry`: Anonymous usage analytics using PostHog. Covers command tracking, opt-out controls, and first-run disclosure notice. ### Modified Capabilities - `global-config`: Add telemetry state storage (anonymous ID, notice seen flag) ## Impact - **Dependencies**: Add `posthog-node` package - **Privacy**: Opt-out via env var, no personal data collected, clear disclosure - **Configuration**: New global config fields for telemetry state - **Network**: Async event sending with flush on exit (~100-300ms added) - **CI/CD**: Telemetry auto-disabled when `CI=true` - **Documentation**: Update README with telemetry disclosure ================================================ FILE: openspec/changes/archive/2026-01-09-add-posthog-analytics/specs/global-config/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Global configuration storage The system SHALL store global configuration in `~/.config/openspec/config.json`, including telemetry state with `anonymousId` and `noticeSeen` fields. #### Scenario: Initial config creation - **WHEN** no global config file exists - **AND** the first telemetry event is about to be sent - **THEN** the system creates `~/.config/openspec/config.json` with telemetry configuration #### Scenario: Telemetry config structure - **WHEN** reading or writing telemetry configuration - **THEN** the config contains a `telemetry` object with `anonymousId` (string UUID) and `noticeSeen` (boolean) fields #### Scenario: Config file format - **WHEN** storing configuration - **THEN** the system writes valid JSON that can be read and modified by users #### Scenario: Existing config preservation - **WHEN** adding telemetry fields to an existing config file - **THEN** the system preserves all existing configuration fields ================================================ FILE: openspec/changes/archive/2026-01-09-add-posthog-analytics/specs/telemetry/spec.md ================================================ ## ADDED Requirements ### Requirement: Command execution tracking The system SHALL send a `command_executed` event to PostHog when any CLI command executes, including only the command name and OpenSpec version as properties. #### Scenario: Standard command execution - **WHEN** a user runs any openspec command - **THEN** the system sends a `command_executed` event with `command` and `version` properties #### Scenario: Subcommand execution - **WHEN** a user runs a nested command like `openspec change apply` - **THEN** the system sends a `command_executed` event with the full command path (e.g., `change:apply`) ### Requirement: Privacy-preserving event design The system SHALL NOT include command arguments, file paths, project names, spec content, error messages, or IP addresses in telemetry events. #### Scenario: Command with arguments - **WHEN** a user runs `openspec init my-project --force` - **THEN** the telemetry event contains only `command: "init"` and `version: ""` without arguments #### Scenario: IP address exclusion - **WHEN** the system sends a telemetry event - **THEN** the event explicitly sets `$ip: null` to prevent IP tracking ### Requirement: Environment variable opt-out The system SHALL disable telemetry when `OPENSPEC_TELEMETRY=0` or `DO_NOT_TRACK=1` environment variables are set. #### Scenario: OPENSPEC_TELEMETRY opt-out - **WHEN** `OPENSPEC_TELEMETRY=0` is set in the environment - **THEN** the system sends no telemetry events #### Scenario: DO_NOT_TRACK opt-out - **WHEN** `DO_NOT_TRACK=1` is set in the environment - **THEN** the system sends no telemetry events #### Scenario: Environment variable takes precedence - **WHEN** the user has previously used the CLI (config exists) - **AND** the user sets `OPENSPEC_TELEMETRY=0` - **THEN** telemetry is disabled regardless of config state ### Requirement: CI environment auto-disable The system SHALL automatically disable telemetry when `CI=true` environment variable is detected. #### Scenario: CI environment detection - **WHEN** `CI=true` is set in the environment - **THEN** the system sends no telemetry events #### Scenario: CI with explicit enable - **WHEN** `CI=true` is set - **AND** `OPENSPEC_TELEMETRY=1` is explicitly set - **THEN** telemetry remains disabled (CI takes precedence for privacy) ### Requirement: First-run telemetry notice The system SHALL display a one-line telemetry disclosure notice on the first command execution, before any telemetry is sent. #### Scenario: First command execution - **WHEN** a user runs their first openspec command - **AND** telemetry is enabled - **THEN** the system displays: "Note: OpenSpec collects anonymous usage stats. Opt out: OPENSPEC_TELEMETRY=0" #### Scenario: Subsequent command execution - **WHEN** a user has already seen the notice (noticeSeen: true in config) - **THEN** the system does not display the notice #### Scenario: Notice before telemetry - **WHEN** displaying the first-run notice - **THEN** the notice appears before any telemetry event is sent ### Requirement: Anonymous user identification The system SHALL generate a random UUID as an anonymous identifier on first telemetry send, stored in global config. #### Scenario: First telemetry event - **WHEN** the first telemetry event is sent - **AND** no anonymousId exists in config - **THEN** the system generates a random UUID v4 and stores it in config #### Scenario: Persistent identity - **WHEN** a user runs multiple commands across sessions - **THEN** the same anonymousId is used for all events #### Scenario: Lazy generation with opt-out - **WHEN** a user opts out before running any command - **THEN** no anonymousId is ever generated or stored ### Requirement: Immediate event sending The system SHALL send telemetry events immediately without batching, using `flushAt: 1` and `flushInterval: 0` configuration. #### Scenario: Event transmission timing - **WHEN** a command executes - **THEN** the telemetry event is sent immediately, not queued for batch transmission ### Requirement: Graceful shutdown The system SHALL call `posthog.shutdown()` before CLI exit to ensure pending events are flushed. #### Scenario: Normal exit - **WHEN** a command completes successfully - **THEN** the system awaits `shutdown()` before exiting #### Scenario: Error exit - **WHEN** a command fails with an error - **THEN** the system still awaits `shutdown()` before exiting ### Requirement: Silent failure handling The system SHALL silently ignore telemetry failures without affecting CLI functionality. #### Scenario: Network failure - **WHEN** the telemetry request fails due to network error - **THEN** the CLI command completes normally without error message #### Scenario: PostHog outage - **WHEN** PostHog service is unavailable - **THEN** the CLI command completes normally without error message #### Scenario: Shutdown failure - **WHEN** `shutdown()` fails or times out - **THEN** the CLI exits normally without error message ================================================ FILE: openspec/changes/archive/2026-01-09-add-posthog-analytics/tasks.md ================================================ ## 1. Setup - [x] 1.1 Add `posthog-node` package as a dependency - [x] 1.2 Create `src/telemetry/` module directory - [x] 1.3 Add PostHog API key configuration (environment variable or embedded) ## 2. Global Config - [x] 2.1 Create or extend global config module for `~/.config/openspec/config.json` - [x] 2.2 Implement read/write functions that preserve existing config fields - [x] 2.3 Define telemetry config structure (`anonymousId`, `noticeSeen`) ## 3. Core Telemetry Module - [x] 3.1 Implement `isTelemetryEnabled()` checking `OPENSPEC_TELEMETRY`, `DO_NOT_TRACK`, and `CI` env vars - [x] 3.2 Implement `getOrCreateAnonymousId()` with lazy UUID generation - [x] 3.3 Initialize PostHog client with `flushAt: 1` and `flushInterval: 0` - [x] 3.4 Implement `trackCommand(commandName, version)` with `$ip: null` - [x] 3.5 Implement `shutdown()` with try/catch for silent failure handling ## 4. First-Run Notice - [x] 4.1 Implement `maybeShowTelemetryNotice()` function - [x] 4.2 Check `noticeSeen` flag before displaying notice - [x] 4.3 Display notice text: "Note: OpenSpec collects anonymous usage stats. Opt out: OPENSPEC_TELEMETRY=0" - [x] 4.4 Update `noticeSeen` in config after first display ## 5. CLI Integration - [x] 5.1 Add Commander.js `preAction` hook to show notice and track command - [x] 5.2 Add Commander.js `postAction` hook to call shutdown - [x] 5.3 Handle subcommand path extraction (e.g., `change:apply`) ## 6. Testing - [x] 6.1 Test opt-out via `OPENSPEC_TELEMETRY=0` - [x] 6.2 Test opt-out via `DO_NOT_TRACK=1` - [x] 6.3 Test auto-disable in CI environment - [x] 6.4 Test first-run notice display and noticeSeen persistence - [x] 6.5 Test anonymous ID generation and persistence - [x] 6.6 Test silent failure on network error (mock PostHog) ## 7. Documentation - [x] 7.1 Add telemetry disclosure section to README - [x] 7.2 Document opt-out methods (`OPENSPEC_TELEMETRY=0`, `DO_NOT_TRACK=1`) - [x] 7.3 Document what data is collected and not collected ================================================ FILE: openspec/changes/archive/2026-01-09-fix-codebuddy-frontmatter-fields/proposal.md ================================================ ## Why CodeBuddy slash command configurator currently uses inconsistent frontmatter fields compared to other tools. It uses `category` and `tags` fields (like Crush) but should use `argument-hint` field (like Factory, Auggie, and Codex) for better consistency. Additionally, the `proposal` command is missing frontmatter fields entirely. After reviewing CodeBuddy's official documentation, the correct format should use `description` and `argument-hint` fields with square bracket parameter format. ## What Changes - Replace `category` and `tags` fields with `argument-hint` field in CodeBuddy frontmatter - Add missing frontmatter fields to the `proposal` command - Use correct square bracket format for `argument-hint` parameters (e.g., `[change-id]`) - Ensure consistency with CodeBuddy's official documentation ## Impact - Affected specs: cli-init, cli-update - Affected code: `src/core/configurators/slash/codebuddy.ts` - CodeBuddy users will get proper argument hints in the correct format for slash commands ================================================ FILE: openspec/changes/archive/2026-01-09-fix-codebuddy-frontmatter-fields/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Slash Command Configuration The init command SHALL generate slash command files for supported editors using shared templates. #### Scenario: Generating slash commands for Antigravity - **WHEN** the user selects Antigravity during initialization - **THEN** create `.agent/workflows/openspec-proposal.md`, `.agent/workflows/openspec-apply.md`, and `.agent/workflows/openspec-archive.md` - **AND** ensure each file begins with YAML frontmatter that contains only a `description: ` field followed by the shared OpenSpec workflow instructions wrapped in managed markers - **AND** populate the workflow body with the same proposal/apply/archive guidance used for other tools so Antigravity behaves like Windsurf while pointing to the `.agent/workflows/` directory #### Scenario: Generating slash commands for Claude Code - **WHEN** the user selects Claude Code during initialization - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for CodeBuddy Code - **WHEN** the user selects CodeBuddy Code during initialization - **THEN** create `.codebuddy/commands/openspec/proposal.md`, `.codebuddy/commands/openspec/apply.md`, and `.codebuddy/commands/openspec/archive.md` - **AND** populate each file from shared templates that include CodeBuddy-compatible YAML frontmatter for the `description` and `argument-hint` fields - **AND** use square bracket format for `argument-hint` parameters (e.g., `[change-id]`) - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cline - **WHEN** the user selects Cline during initialization - **THEN** create `.clinerules/workflows/openspec-proposal.md`, `.clinerules/workflows/openspec-apply.md`, and `.clinerules/workflows/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include Cline-specific Markdown heading frontmatter - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Crush - **WHEN** the user selects Crush during initialization - **THEN** create `.crush/commands/openspec/proposal.md`, `.crush/commands/openspec/apply.md`, and `.crush/commands/openspec/archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** include Crush-specific frontmatter with OpenSpec category and tags - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Cursor - **WHEN** the user selects Cursor during initialization - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Factory Droid - **WHEN** the user selects Factory Droid during initialization - **THEN** create `.factory/commands/openspec-proposal.md`, `.factory/commands/openspec-apply.md`, and `.factory/commands/openspec-archive.md` - **AND** populate each file from shared templates that include Factory-compatible YAML frontmatter for the `description` and `argument-hint` fields - **AND** include the `$ARGUMENTS` placeholder in the template body so droid receives any user-supplied input - **AND** wrap the generated content in OpenSpec managed markers so `openspec update` can safely refresh the commands #### Scenario: Generating slash commands for OpenCode - **WHEN** the user selects OpenCode during initialization - **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md` - **AND** populate each file from shared templates so command text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Windsurf - **WHEN** the user selects Windsurf during initialization - **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Kilo Code - **WHEN** the user selects Kilo Code during initialization - **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md` - **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools - **AND** each template includes instructions for the relevant OpenSpec workflow stage #### Scenario: Generating slash commands for Codex - **WHEN** the user selects Codex during initialization - **THEN** create global prompt files at `~/.codex/prompts/openspec-proposal.md`, `~/.codex/prompts/openspec-apply.md`, and `~/.codex/prompts/openspec-archive.md` (or under `$CODEX_HOME/prompts` if set) - **AND** populate each file from shared templates that map the first numbered placeholder (`$1`) to the primary user input (e.g., change identifier or question text) - **AND** wrap the generated content in OpenSpec markers so `openspec update` can refresh the prompts without touching surrounding custom notes ================================================ FILE: openspec/changes/archive/2026-01-09-fix-codebuddy-frontmatter-fields/specs/cli-update/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Slash Command Updates The update command SHALL refresh existing slash command files for configured tools without creating new ones, and ensure the OpenCode archive command accepts change ID arguments. #### Scenario: Updating slash commands for Antigravity - **WHEN** `.agent/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh the OpenSpec-managed portion of each file so the workflow copy matches other tools while preserving the existing single-field `description` frontmatter - **AND** skip creating any missing workflow files during update, mirroring the behavior for Windsurf and other IDEs #### Scenario: Updating slash commands for Claude Code - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for CodeBuddy Code - **WHEN** `.codebuddy/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` - **THEN** refresh each file using the shared CodeBuddy templates that include YAML frontmatter for the `description` and `argument-hint` fields - **AND** use square bracket format for `argument-hint` parameters (e.g., `[change-id]`) - **AND** preserve any user customizations outside the OpenSpec managed markers #### Scenario: Updating slash commands for Cline - **WHEN** `.clinerules/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** include Cline-specific Markdown heading frontmatter - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Crush - **WHEN** `.crush/commands/` contains `openspec/proposal.md`, `openspec/apply.md`, and `openspec/archive.md` - **THEN** refresh each file using shared templates - **AND** include Crush-specific frontmatter with OpenSpec category and tags - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Cursor - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage #### Scenario: Updating slash commands for Factory Droid - **WHEN** `.factory/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using the shared Factory templates that include YAML frontmatter for the `description` and `argument-hint` fields - **AND** ensure the template body retains the `$ARGUMENTS` placeholder so user input keeps flowing into droid - **AND** update only the content inside the OpenSpec managed markers, leaving any unmanaged notes untouched - **AND** skip creating missing files during update #### Scenario: Updating slash commands for OpenCode - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage - **AND** ensure the archive command includes `$ARGUMENTS` placeholder in frontmatter for accepting change ID arguments #### Scenario: Updating slash commands for Windsurf - **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` - **THEN** refresh each file using shared templates - **AND** ensure templates include instructions for the relevant workflow stage ================================================ FILE: openspec/changes/archive/2026-01-09-fix-codebuddy-frontmatter-fields/tasks.md ================================================ ## 1. Implementation - [x] 1.1 Update CodeBuddy frontmatter to use `argument-hint` instead of `category` and `tags` - [x] 1.2 Add missing frontmatter fields to the `proposal` command - [x] 1.3 Ensure all three commands (proposal, apply, archive) have consistent frontmatter structure - [x] 1.4 Test the changes by running `openspec init` and `openspec update` ================================================ FILE: openspec/changes/archive/2026-01-15-add-nix-ci-validation/design.md ================================================ # Design: Nix CI Validation ## Context OpenSpec recently added Nix flake support to enable Nix users to install the tool. This includes: - `flake.nix`: Nix package definition with pnpm dependency fetching - `scripts/update-flake.sh`: Automation script to update version and hash when releasing Currently, there is no CI validation ensuring these Nix artifacts remain functional. The existing CI workflow (.github/workflows/ci.yml) validates Node.js builds, tests, and linting across multiple platforms (Linux, macOS, Windows) but does not validate Nix builds. **Stakeholders**: Nix users, maintainers, contributors who need confidence that Nix support works. **Constraints**: - Must work in GitHub Actions Linux runners - Should minimize CI runtime impact (<5 minutes added) - Should support local testing with `act` for rapid iteration - Must integrate with existing required checks ## Goals / Non-Goals **Goals**: - Validate `nix build` succeeds on every PR/push - Validate `scripts/update-flake.sh` executes without errors - Ensure Nix support doesn't regress silently - Support local testing with `act` - Optimize with caching to minimize CI time **Non-Goals**: - Testing on macOS (GitHub-hosted macOS runners are slower and more expensive; Nix flake already declares macOS support) - Building for all declared systems (x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin) - focus on most common platform - Validating Nix flake quality/style (nixpkgs-fmt, etc.) - can be added later if needed - Running OpenSpec's full test suite through Nix build - existing CI already does this ## Decisions ### Decision 1: Use DeterminateSystems nix-installer-action **What**: Use `determinatesystems/nix-installer-action` for installing Nix in CI. **Why**: - Official GitHub Action maintained by Determinate Systems (Nix experts) - Handles GitHub Actions environment quirks automatically - Includes automatic caching configuration - More reliable than curl | sh installation script - Better error messages and diagnostics **Alternatives considered**: - Official Nix installer (`curl -L https://nixos.org/nix/install | sh`): Works but requires manual setup of flakes, caching, and CI-specific configuration - `cachix/install-nix-action`: Popular alternative but determinatesystems is more actively maintained and has better GHA integration ### Decision 2: Use Magic Nix Cache for performance **What**: Use `determinatesystems/magic-nix-cache-action` for automatic binary caching. **Why**: - Zero-configuration caching for Nix store - Significantly reduces CI time on subsequent runs (from ~5min to ~1-2min) - Free for public repositories - Handles cache keys automatically **Alternatives considered**: - Manual Nix store caching with GitHub Actions cache: More complex, requires manual cache key management - Cachix: Excellent tool but requires account setup and token management - No caching: Acceptable for initial implementation, but poor developer experience ### Decision 3: Separate job for Nix validation **What**: Create a dedicated `nix-validate` job in .github/workflows/ci.yml that runs in parallel with other jobs. **Why**: - Keeps Nix validation isolated from Node.js validation - Allows parallel execution for faster CI - Easier to debug when Nix-specific issues occur - Can be marked as required check independently **Alternatives considered**: - Add Nix steps to existing jobs: Creates coupling between Node.js and Nix validation, harder to maintain - Separate workflow file: Overkill for a single job, harder to manage required checks ### Decision 4: Validate update script by executing it **What**: Run `scripts/update-flake.sh` as part of CI validation. **Why**: - Ensures the script doesn't break due to changes in package.json format, nix build output, or dependencies - Tests the full workflow users will follow when releasing - Catches errors early **Implementation approach**: - Execute script in a way that doesn't modify git state (or discard changes after) - Verify script exits with code 0 - Optionally validate that flake.nix contains expected patterns after execution **Alternatives considered**: - Mock/dry-run mode: Would require modifying the script significantly - Skip validation: Risky - script could break and only be discovered at release time - Only run on release branches: Misses issues early in development ### Decision 5: Run on pull_request and push to main **What**: Configure Nix validation job to run on: - `pull_request` events (any PR to main) - `push` events (direct pushes to main) - `workflow_dispatch` (manual trigger for testing) **Why**: - Catches issues before merge (pull_request) - Validates main branch stays healthy (push) - Allows manual testing without creating PRs (workflow_dispatch) ### Decision 6: Support act for local testing **What**: Ensure workflow is compatible with `act` tool for local CI testing. **Why**: - Faster iteration when developing CI changes - Allows testing without pushing to GitHub - Reduces commit noise from CI debugging **Requirements**: - Use standard GitHub Actions syntax - Document any act-specific configuration needed - Test that Nix can be installed in act's Docker containers **Limitations**: - act may not perfectly replicate GitHub's runners, but close enough for validation ## Risks / Trade-offs ### Risk: CI runtime increase **Impact**: Adding Nix validation will increase total CI time by 2-5 minutes per run. **Mitigation**: - Run Nix job in parallel with existing jobs (no blocking delay) - Use magic-nix-cache for subsequent runs (~1-2 min with cache) - Configure appropriate timeout (10 minutes max) **Acceptance**: The benefit of preventing Nix regressions outweighs the cost. ### Risk: Nix installer failures in CI **Impact**: Transient failures in Nix installation could block PRs. **Mitigation**: - Use determinatesystems action which has retry logic - Monitor for flaky failures and adjust if needed - Document troubleshooting steps **Acceptance**: Nix installation is generally stable in GHA; this is low risk. ### Risk: Update script modifies git state **Impact**: Running update-flake.sh modifies flake.nix, which could cause CI to fail if git state is checked. **Mitigation**: - Run script in isolation without committing changes - Add `git checkout -- flake.nix` after validation - Or accept dirty git state in CI (doesn't affect build validation) **Acceptance**: Script validation is important enough to handle this carefully. ### Risk: act compatibility issues **Impact**: Workflow might not work perfectly with act due to Docker environment differences. **Mitigation**: - Document known limitations - Focus on GitHub Actions as primary validation target - Use act as best-effort local testing **Acceptance**: act support is nice-to-have, not required. ## Migration Plan ### Phase 1: Add Nix job (new, non-required) 1. Add `nix-validate` job to .github/workflows/ci.yml 2. Configure to run in parallel with existing jobs 3. Do NOT mark as required check initially 4. Monitor for ~1 week to ensure stability ### Phase 2: Make required 1. After validation is stable, add to required checks 2. Update branch protection rules in GitHub settings 3. Document in CONTRIBUTING.md or README ### Rollback Plan If Nix validation causes issues: 1. Remove job from required checks in GitHub settings (immediate) 2. Comment out or remove job from workflow (permanent fix) 3. Investigate and fix issues 4. Re-enable following same phased approach ## Open Questions - **Q**: Should we test update-flake.sh on every CI run, or only when package.json or pnpm-lock.yaml changes? - **A**: Test on every run for simplicity. The script is fast (<30 seconds) and catching regressions is valuable. - **Q**: Should we validate on macOS as well? - **A**: No for initial implementation. Linux validation is sufficient and macOS runners are slower/more expensive. Can add later if users report macOS-specific issues. - **Q**: Should we run full OpenSpec tests through the Nix build? - **A**: No. The Nix build already runs `pnpm test` as part of its build phase. Existing CI jobs cover testing thoroughly. Nix validation focuses on build success. - **Q**: What timeout should we use for the Nix validation job? - **A**: Start with 10 minutes. With caching, jobs should complete in 1-3 minutes. Without cache (first run), 5-7 minutes is expected. ================================================ FILE: openspec/changes/archive/2026-01-15-add-nix-ci-validation/proposal.md ================================================ # Add Nix CI Validation ## Why The project recently added Nix flake support (flake.nix) and an automated update script (scripts/update-flake.sh) to enable Nix users to install OpenSpec. However, there is no CI validation ensuring these Nix artifacts continue to work as the project evolves. This creates risk that breaking changes could be merged without detection. ## What Changes - Add a new GitHub Actions workflow job to validate Nix flake builds successfully - Add validation that the update-flake.sh script executes without errors - Test on Linux (where Nix support is most common) - Ensure CI fails if Nix build or update script breaks - Enable local testing with `act` for developers ## Impact - Affected specs: New capability `ci-nix-validation` - Affected code: `.github/workflows/ci.yml` (add new job) - Affected infrastructure: GitHub Actions runners with Nix installed - Benefits: Prevents regressions in Nix support, gives confidence to Nix users - Trade-offs: Adds ~2-3 minutes to CI runtime ================================================ FILE: openspec/changes/archive/2026-01-15-add-nix-ci-validation/specs/ci-nix-validation/spec.md ================================================ # CI Nix Validation Specification ## ADDED Requirements ### Requirement: Nix Flake Build Validation The CI system SHALL validate that the Nix flake builds successfully on every pull request and push to main. #### Scenario: Successful flake build - **WHEN** a pull request or push to main is made - **THEN** the CI SHALL execute `nix build` and verify it completes with exit code 0 - **AND** the build output SHALL contain the openspec binary #### Scenario: Flake build failure - **WHEN** the Nix flake configuration is broken - **THEN** the CI job SHALL fail with a non-zero exit code - **AND** the CI SHALL prevent merging of the pull request #### Scenario: Multi-platform support check - **WHEN** the flake declares support for multiple systems - **THEN** the CI SHALL validate the flake builds on at least Linux (x86_64-linux) ### Requirement: Update Script Validation The CI system SHALL validate that the update-flake.sh script executes successfully and produces valid output. #### Scenario: Update script execution - **WHEN** the CI runs the update script validation - **THEN** the script SHALL execute without errors - **AND** the script SHALL correctly extract the version from package.json - **AND** the script SHALL update flake.nix with the correct version #### Scenario: Update script with mock hash - **WHEN** validating the update script in CI - **THEN** the script SHALL be able to detect and extract the correct pnpm dependency hash - **AND** the flake.nix SHALL be updated with a valid sha256 hash ### Requirement: CI Job Integration The Nix validation jobs SHALL be integrated into the existing GitHub Actions workflow and required for merge. #### Scenario: PR merge requirements - **WHEN** a pull request is created - **THEN** the Nix validation job SHALL be included in required checks - **AND** the PR SHALL NOT be mergeable until Nix validation passes #### Scenario: Job execution triggers - **WHEN** code is pushed to a pull request OR pushed to main OR manually triggered - **THEN** the Nix validation job SHALL execute automatically ### Requirement: Local Testing Support The CI workflow SHALL be testable locally using the `act` tool to enable rapid iteration. #### Scenario: Local CI execution with act - **WHEN** a developer runs `act` with the Nix validation workflow - **THEN** the workflow SHALL execute in the local Docker environment - **AND** the developer SHALL receive feedback on Nix build status without pushing to GitHub #### Scenario: Act configuration compatibility - **WHEN** the workflow is designed - **THEN** it SHALL use standard GitHub Actions syntax compatible with `act` - **AND** any Nix-specific setup SHALL work in the act Docker environment ### Requirement: Nix Installation in CI The CI environment SHALL have Nix properly installed and configured before running validation. #### Scenario: Nix installation step - **WHEN** the Nix validation job starts - **THEN** Nix SHALL be installed using the official Nix installer or determinatesystems/nix-installer-action - **AND** the Nix installation SHALL be cached for subsequent runs to improve performance #### Scenario: Nix configuration for CI - **WHEN** Nix is installed in CI - **THEN** it SHALL be configured to work in the GitHub Actions environment - **AND** experimental features (flakes, nix-command) SHALL be enabled ### Requirement: CI Performance Optimization The Nix validation SHALL be optimized to minimize CI runtime impact. #### Scenario: Acceptable runtime - **WHEN** the Nix validation job runs - **THEN** it SHALL complete in under 5 minutes on a clean run - **AND** with caching, it SHALL complete in under 3 minutes on subsequent runs #### Scenario: Parallel execution - **WHEN** multiple CI jobs are running - **THEN** the Nix validation job SHALL run in parallel with other validation jobs (tests, lint) - **AND** SHALL NOT block other independent checks ================================================ FILE: openspec/changes/archive/2026-01-15-add-nix-ci-validation/tasks.md ================================================ # Implementation Tasks ## 1. Add Nix Installation to CI - [x] 1.1 Research Nix installation options for GitHub Actions (nix-installer-action vs manual install) - [x] 1.2 Add Nix installation step to .github/workflows/ci.yml - [x] 1.3 Configure Nix with experimental features enabled (flakes, nix-command) - [x] 1.4 Add Nix store caching to improve CI performance ## 2. Create Nix Build Validation Job - [x] 2.1 Add new `nix-flake-validate` job to .github/workflows/ci.yml - [x] 2.2 Implement `nix build` step with proper error handling - [x] 2.3 Add verification step to confirm binary exists in build output - [x] 2.4 Add step to test binary execution (`nix run . -- --version`) ## 3. Add Update Script Validation - [x] 3.1 Add job step to run scripts/update-flake.sh in dry-run or test mode - [x] 3.2 Verify script executes without errors - [x] 3.3 Add validation that version is correctly extracted from package.json - [x] 3.4 Verify flake.nix is updated with correct format (version and hash) ## 4. Configure Job Dependencies and Requirements - [x] 4.1 Configure Nix validation job to run on pull_request and push events - [x] 4.2 Add Nix validation to required checks list - [x] 4.3 Configure job to run in parallel with existing test/lint jobs - [x] 4.4 Set appropriate timeout (5-10 minutes) ## 5. Test with act Locally - [x] 5.1 Install act locally if not already available - [x] 5.2 Test Nix validation job using `act pull_request` - [x] 5.3 Verify act can run the workflow with Nix installed - [x] 5.4 Document any act-specific configuration needed in .actrc or README ## 6. Documentation and Finalization - [x] 6.1 Add documentation about Nix CI validation to README or CONTRIBUTING.md - [x] 6.2 Document how to test CI locally with act - [ ] 6.3 Update CI badge or status indicators if needed - [ ] 6.4 Test end-to-end by creating a test PR ## 7. Archive Change - [x] 7.1 After merge and verification, create new spec file at openspec/specs/ci-nix-validation/spec.md - [x] 7.2 Move change directory to openspec/changes/archive/[date]-add-nix-ci-validation/ - [x] 7.3 Run `openspec validate --strict` to confirm archived change passes ================================================ FILE: openspec/changes/archive/2026-01-30-opencode-command-references/.openspec.yaml ================================================ schema: spec-driven created: 2026-01-30 ================================================ FILE: openspec/changes/archive/2026-01-30-opencode-command-references/README.md ================================================ # opencode-command-references Transform /opsx: to /opsx- in both commands and skills for OpenCode ================================================ FILE: openspec/changes/archive/2026-01-30-opencode-command-references/design.md ================================================ ## Context OpenCode is one of many supported AI tools. Each tool has: - A **command adapter** (in `src/core/command-generation/adapters/`) for generating tool-specific command files - **Skills** generated via `generateSkillContent()` in `src/core/shared/skill-generation.ts` Currently: - Commands go through the adapter system which can transform content per-tool - Skills use a single shared function with no tool-specific transformation The templates in `src/core/templates/skill-templates.ts` use Claude's colon-based format (`/opsx:new`) as the canonical format. Tools that use different formats need transformation at generation time. ## Goals / Non-Goals **Goals:** - Transform all `/opsx:` command references to `/opsx-` for OpenCode in both commands and skills - Create a shared, reusable transformation utility - Keep the transformation opt-in via a callback parameter (not hard-coded tool detection) **Non-Goals:** - Modifying the canonical template format (templates stay with `/opsx:`) - Applying transformation to other tools (only OpenCode for now) - Creating a full adapter system for skills (overkill for current needs) ## Decisions ### Decision 1: Shared Utility Function **Choice**: Create `transformToHyphenCommands()` in `src/utils/command-references.ts` **Rationale**: - Single source of truth for the transformation logic - Can be used by both command adapter and skill generation - Easy to test in isolation - Follows existing utils pattern in the codebase **Alternatives considered**: - Inline the transformation in each location - Duplicates logic, harder to maintain ### Decision 2: Callback Parameter for Skill Generation **Choice**: Add optional `transformInstructions?: (instructions: string) => string` parameter to `generateSkillContent()` **Rationale**: - Flexible - callers define the transformation, not the generation function - No coupling - `generateSkillContent()` doesn't need to know about tool formats - Extensible - could support other transformations in the future - Follows inversion of control principle **Alternatives considered**: - Add tool ID parameter and switch on it - Creates coupling, harder to extend - Create skill adapter system parallel to commands - Over-engineering for current needs - Transform in templates directly - Breaks single-source-of-truth principle ### Decision 3: Apply at Generation Sites **Choice**: Pass transformer in `init.ts` and `update.ts` when `tool.value === 'opencode'` **Rationale**: - These are the only two places that generate skills - Simple conditional check, no new abstractions needed - Easy to extend to other tools if needed later ## Risks / Trade-offs | Risk | Mitigation | |------|------------| | Other `/opsx:` patterns exist that shouldn't be transformed | All occurrences in templates are command invocations - verified by inspection | | Future tools may need same transformation | Utility is shared and easy to reuse; can add to other tools' generation | | Callback adds complexity to function signature | Optional parameter with sensible default (no transformation) | ================================================ FILE: openspec/changes/archive/2026-01-30-opencode-command-references/proposal.md ================================================ ## Why OpenCode uses hyphen-based command syntax (`/opsx-new`) but our templates contain colon-based references (`/opsx:new`). This creates inconsistency where generated command files and skill files contain references that don't match the actual command invocation syntax, confusing both the AI and users. ## What Changes - Create a shared transformation utility (`transformToHyphenCommands`) for converting `/opsx:` to `/opsx-` - Update the OpenCode command adapter to transform body text using this utility - Add an optional `transformInstructions` callback parameter to `generateSkillContent()` - Update `init.ts` and `update.ts` to pass the transformer when generating skills for OpenCode ## Capabilities ### New Capabilities None - this is a bug fix, not a new capability. ### Modified Capabilities None - no spec-level behavior changes. This is an implementation fix in the OpenCode adapter and skill generation that doesn't change any external requirements or contracts. ## Impact - **Code**: - `src/utils/command-references.ts` (new file) - `src/utils/index.ts` (export) - `src/core/shared/skill-generation.ts` (add callback parameter) - `src/core/command-generation/adapters/opencode.ts` (use transformer) - `src/core/init.ts` (pass transformer for OpenCode) - `src/core/update.ts` (pass transformer for OpenCode) - **Users**: OpenCode users will see correct `/opsx-` command references in both generated command files AND skill files - **Other tools**: No impact - transformation only applies to OpenCode ================================================ FILE: openspec/changes/archive/2026-01-30-opencode-command-references/specs/no-changes.md ================================================ # No Spec Changes This is a bug fix that doesn't modify any external requirements or contracts. The proposal's Capabilities section indicates: - **New Capabilities**: None - **Modified Capabilities**: None No spec files are needed for this implementation-only fix. ================================================ FILE: openspec/changes/archive/2026-01-30-opencode-command-references/tasks.md ================================================ ## 1. Implementation - [x] 1.1 Create `src/utils/command-references.ts` with `transformToHyphenCommands()` function - [x] 1.2 Export `transformToHyphenCommands` from `src/utils/index.ts` - [x] 1.3 Update `generateSkillContent()` in `src/core/shared/skill-generation.ts` to accept optional `transformInstructions` callback - [x] 1.4 Update OpenCode adapter in `src/core/command-generation/adapters/opencode.ts` to use `transformToHyphenCommands()` for body text - [x] 1.5 Update `init.ts` to pass transformer when generating skills for OpenCode - [x] 1.6 Update `update.ts` to pass transformer when generating skills for OpenCode ## 2. Testing - [x] 2.1 Create `test/utils/command-references.test.ts` with unit tests for `transformToHyphenCommands()` - [x] 2.2 Add test to `test/core/command-generation/adapters.test.ts` for OpenCode body transformation - [x] 2.3 Add test to `test/core/shared/skill-generation.test.ts` for transformer callback ## 3. Verification - [x] 3.1 Run `npx vitest run test/utils/command-references.test.ts test/core/command-generation/adapters.test.ts test/core/shared/skill-generation.test.ts` to ensure tests pass - [x] 3.2 Run `pnpm run build` to ensure no TypeScript errors - [x] 3.3 Run `openspec init --tools opencode` in a temp directory and verify: - Command files in `.opencode/command/` contain `/opsx-` references (not `/opsx:`) - Skill files in `.opencode/skills/` contain `/opsx-` references (not `/opsx:`) ================================================ FILE: openspec/changes/archive/2026-02-17-add-feedback-command/proposal.md ================================================ ## Why Users and agents need a simple way to submit feedback about OpenSpec directly from the CLI. Currently there's no mechanism to collect user feedback, feature requests, or bug reports in a way that enables follow-up conversation. Using GitHub Issues allows us to track feedback, prevent spam via GitHub auth, and enables outreach to users. ## What Changes - Add `openspec feedback ` CLI command - Leverage `gh` CLI for GitHub authentication and issue creation - Add `/feedback` skill for agent-assisted feedback with context enrichment - Ensure cross-platform compatibility (macOS, Linux, Windows) ## Impact - Affected specs: New `cli-feedback` capability - Affected code: - `src/cli/index.ts` - Register feedback command - `src/commands/feedback.ts` - Command implementation using `gh` CLI - `src/core/templates/skill-templates.ts` - Feedback skill template - `src/core/completions/command-registry.ts` - Shell completions - External dependency: Requires `gh` CLI installed and authenticated ================================================ FILE: openspec/changes/archive/2026-02-17-add-feedback-command/specs/cli-feedback/spec.md ================================================ ## ADDED Requirements ### Requirement: Feedback command The system SHALL provide an `openspec feedback` command that creates a GitHub Issue in the openspec repository using the `gh` CLI. The system SHALL use `execFileSync` with argument arrays to prevent shell injection vulnerabilities. #### Scenario: Simple feedback submission - **WHEN** user executes `openspec feedback "Great tool!"` - **THEN** the system executes `gh issue create` with title "Feedback: Great tool!" - **AND** the issue is created in the openspec repository - **AND** the issue has the `feedback` label - **AND** the system displays the created issue URL #### Scenario: Safe command execution - **WHEN** submitting feedback via `gh` CLI - **THEN** the system uses `execFileSync` with separate arguments array - **AND** user input is NOT passed through a shell - **AND** shell metacharacters (quotes, backticks, $(), etc.) are treated as literal text #### Scenario: Feedback with body - **WHEN** user executes `openspec feedback "Title here" --body "Detailed description..."` - **THEN** the system creates a GitHub Issue with the specified title - **AND** the issue body contains the detailed description - **AND** the issue body includes metadata (OpenSpec version, platform, timestamp) ### Requirement: GitHub CLI dependency The system SHALL use `gh` CLI for automatic feedback submission when available, and provide a manual submission fallback when `gh` is not installed or not authenticated. The system SHALL use platform-appropriate commands to detect `gh` CLI availability. #### Scenario: Missing gh CLI with fallback - **WHEN** user runs `openspec feedback "message"` - **AND** `gh` CLI is not installed (not found in PATH) - **THEN** the system displays warning: "GitHub CLI not found. Manual submission required." - **AND** outputs structured feedback content with delimiters: - "--- FORMATTED FEEDBACK ---" - Title line - Labels line - Body content with metadata - "--- END FEEDBACK ---" - **AND** displays pre-filled GitHub issue URL for manual submission - **AND** exits with zero code (successful fallback) #### Scenario: Cross-platform gh CLI detection on Unix - **WHEN** system is running on macOS or Linux (platform is 'darwin' or 'linux') - **AND** checking if `gh` CLI is installed - **THEN** the system executes `which gh` command #### Scenario: Cross-platform gh CLI detection on Windows - **WHEN** system is running on Windows (platform is 'win32') - **AND** checking if `gh` CLI is installed - **THEN** the system executes `where gh` command #### Scenario: Unauthenticated gh CLI with fallback - **WHEN** user runs `openspec feedback "message"` - **AND** `gh` CLI is installed but not authenticated - **THEN** the system displays warning: "GitHub authentication required. Manual submission required." - **AND** outputs structured feedback content (same format as missing gh CLI scenario) - **AND** displays pre-filled GitHub issue URL for manual submission - **AND** displays authentication instructions: "To auto-submit in the future: gh auth login" - **AND** exits with zero code (successful fallback) #### Scenario: Authenticated gh CLI - **WHEN** user runs `openspec feedback "message"` - **AND** `gh auth status` returns success (authenticated) - **THEN** the system proceeds with feedback submission ### Requirement: Issue metadata The system SHALL include relevant metadata in the GitHub Issue body. #### Scenario: Standard metadata - **WHEN** creating a GitHub Issue for feedback - **THEN** the issue body includes: - OpenSpec CLI version - Platform (darwin, linux, win32) - Submission timestamp - Separator line: "---\nSubmitted via OpenSpec CLI" #### Scenario: Windows platform metadata - **WHEN** creating a GitHub Issue for feedback on Windows - **THEN** the issue body includes "Platform: win32" - **AND** all platform detection uses Node.js `os.platform()` API #### Scenario: No sensitive metadata - **WHEN** creating a GitHub Issue for feedback - **THEN** the issue body does NOT include: - File paths from user's system - Project names or directory names - Environment variables - IP addresses ### Requirement: Feedback always works The system SHALL allow feedback submission regardless of telemetry settings. #### Scenario: Feedback with telemetry disabled - **WHEN** user has disabled telemetry via `OPENSPEC_TELEMETRY=0` - **AND** user runs `openspec feedback "message"` - **THEN** the feedback is still submitted via `gh` CLI - **AND** telemetry events are not sent #### Scenario: Feedback in CI environment - **WHEN** `CI=true` is set in the environment - **AND** user runs `openspec feedback "message"` - **THEN** the feedback submission proceeds normally (if `gh` is available and authenticated) ### Requirement: Error handling The system SHALL handle feedback submission errors gracefully. #### Scenario: gh CLI execution failure - **WHEN** `gh issue create` command fails - **THEN** the system displays the error output from `gh` CLI - **AND** exits with the same exit code as `gh` #### Scenario: Network failure - **WHEN** `gh` CLI reports network connectivity issues - **THEN** the system displays the error message from `gh` - **AND** suggests checking network connectivity - **AND** exits with non-zero code ### Requirement: Feedback skill for agents The system SHALL provide a `/feedback` skill that guides agents through collecting and submitting user feedback. #### Scenario: Agent-initiated feedback - **WHEN** user invokes `/feedback` in an agent conversation - **THEN** the agent gathers context from the conversation - **AND** drafts a feedback issue with enriched content - **AND** anonymizes sensitive information - **AND** presents the draft to the user for approval - **AND** submits via `openspec feedback` command on user confirmation #### Scenario: Context enrichment - **WHEN** agent drafts feedback - **THEN** the agent includes relevant context such as: - What task was being performed - What worked well or poorly - Specific friction points or praise #### Scenario: Anonymization - **WHEN** agent drafts feedback - **THEN** the agent removes or replaces: - File paths with `` or generic descriptions - API keys, tokens, secrets with `` - Company/organization names with `` - Personal names with `` - Specific URLs with `` unless public/relevant #### Scenario: User confirmation required - **WHEN** agent has drafted feedback - **THEN** the agent MUST show the complete draft to the user - **AND** ask for explicit approval before submitting - **AND** allow the user to request modifications - **AND** only submit after user confirms ### Requirement: Shell completions The system SHALL provide shell completions for the feedback command. #### Scenario: Command completion - **WHEN** user types `openspec fee` - **THEN** the shell completes to `openspec feedback` #### Scenario: Flag completion - **WHEN** user types `openspec feedback "msg" --` - **THEN** the shell suggests available flags (`--body`) ================================================ FILE: openspec/changes/archive/2026-02-17-add-feedback-command/tasks.md ================================================ ## 1. Feedback Command - [x] 1.1 Create `src/commands/feedback.ts` with command implementation - [x] 1.2 Check `gh` CLI availability using platform-appropriate command (`which` on Unix/macOS, `where` on Windows) - [x] 1.3 Check GitHub auth status with `gh auth status` - [x] 1.4 Execute `gh issue create` with formatted title and body using `execFileSync` to prevent shell injection - [x] 1.5 Display issue URL returned by `gh` CLI - [x] 1.6 Register `feedback ` command in `src/cli/index.ts` - [x] 1.7 Ensure cross-platform compatibility (macOS, Linux, Windows) ## 2. Shell Completions - [x] 2.1 Add `feedback` command to command registry - [x] 2.2 Regenerate completion scripts for all shells ## 3. Feedback Skill - [x] 3.1 Create feedback skill template in `skill-templates.ts` - [x] 3.2 Document context gathering workflow - [x] 3.3 Document anonymization rules - [x] 3.4 Document user confirmation flow ## 4. Testing - [x] 4.1 Add unit tests for feedback command (mock `gh` subprocess calls) - [x] 4.2 Add integration test for full feedback flow with mocked `gh` CLI - [x] 4.3 Test error handling for missing `gh` CLI - [x] 4.4 Test error handling for unauthenticated `gh` session - [x] 4.5 Test cross-platform `gh` CLI detection (verify `which` on Unix, `where` on Windows) - [x] 4.6 Test platform metadata includes correct value for Windows (win32) ================================================ FILE: openspec/changes/archive/2026-02-17-add-opsx-onboard-skill/.openspec.yaml ================================================ schema: spec-driven created: 2026-01-24 ================================================ FILE: openspec/changes/archive/2026-02-17-add-opsx-onboard-skill/design.md ================================================ ## Context OpenSpec has a complete skill and slash command generation system. Skills are defined in `src/core/templates/skill-templates.ts` as functions that return `SkillTemplate` objects (for Agent Skills) and `CommandTemplate` objects (for slash commands). These are registered in `src/core/shared/skill-generation.ts` and generated during `openspec init` and `openspec update`. Existing skills follow a consistent pattern: - `getXxxSkillTemplate()` returns the skill with name, description, instructions - `getOpsxXxxCommandTemplate()` returns the slash command with name, description, category, tags, content - Both are registered in their respective arrays in `skill-generation.ts` ## Goals / Non-Goals **Goals:** - Add `/opsx:onboard` skill that teaches the OpenSpec workflow through guided practice - Follow existing patterns for skill/command template generation - Provide comprehensive narration that explains each step - Include codebase analysis to suggest real, appropriately-scoped tasks **Non-Goals:** - Creating a separate "demo mode" or simulated workflow (we do real work) - Adding new CLI commands (this is purely agent instructions) - Modifying the init/update flow (just adding to the template arrays) ## Decisions ### Decision 1: Single Monolithic Skill The onboard skill will be a single comprehensive instruction set rather than composing existing skills with flags. **Rationale:** - Slash commands don't support flags (they're just prompts) - A monolithic skill gives complete control over narration and pacing - Easier to maintain a single cohesive experience - Users learn the real commands by seeing them mentioned in narration ### Decision 2: Codebase Analysis Patterns The skill instructions will direct the agent to look for specific patterns when suggesting starter tasks: 1. TODO/FIXME comments in code 2. Missing error handling (`catch` blocks that swallow errors, no try-catch around risky operations) 3. Functions without tests (cross-reference src/ with test files) 4. Type: `any` in TypeScript files 5. Console.log statements in non-debug code 6. Missing input validation on user-facing inputs 7. Recent git commits (for context on what user is working on) **Rationale:** These are universally applicable, easy to detect, and produce well-scoped tasks. ### Decision 3: Narration Integration Style Each phase will follow a pattern: 1. **EXPLAIN** what we're about to do and why (1-2 sentences) 2. **DO** the action (run command, create artifact) 3. **SHOW** what happened 4. **PAUSE** at key transitions (not every step) Pauses occur at: - After task selection (before creating change) - After drafting proposal (before saving) - After tasks are generated (before implementation) - After archive (final recap) **Rationale:** Too many pauses becomes tedious. Too few loses the teaching opportunity. These are the natural "chapter breaks." ### Decision 4: Scope Guardrail Approach When user selects a task that's too large, the skill will: 1. Acknowledge the task is valuable 2. Explain why smaller is better for first time 3. Suggest a smaller slice or alternative 4. Let user override if they insist **Rationale:** Soft guardrails teach without frustrating. Users learn scope calibration as part of the experience. ### Decision 5: Template Structure The skill template will be ~400-600 lines of instruction text, structured as: ``` - Preflight checks (init status) - Phase 1: Welcome & Setup - Phase 2: Task Selection (with codebase analysis instructions) - Phase 3: Explore Demo (brief) - Phase 4: Change Creation - Phase 5: Proposal - Phase 6: Specs - Phase 7: Design - Phase 8: Tasks - Phase 9: Apply (Implementation) - Phase 10: Archive - Phase 11: Recap & Next Steps - Edge cases & graceful exits ``` The command template will be identical to the skill template (same content, different wrapper). **Rationale:** Following the established pattern where skill and command share the same core instructions. ## Risks / Trade-offs **Risk: Instruction length** The skill will be significantly longer than existing skills (~500 lines vs ~100-200). → Mitigation: This is acceptable since onboarding is inherently comprehensive. Token cost is one-time per session. **Risk: Codebase analysis may find nothing** Some codebases (new projects, very clean code) may not have obvious improvement opportunities. → Mitigation: Fall back to asking user what they want to build. Include "add a new feature" as an option. **Risk: Task suggestions may be inappropriate** Agent might suggest tasks that touch sensitive code or have hidden complexity. → Mitigation: User always chooses; agent just suggests. Scope estimates help set expectations. **Risk: User abandons mid-way** Onboarding takes ~15 minutes; users may not complete it. → Mitigation: Graceful exit handling - note the change is saved, explain how to continue later. ================================================ FILE: openspec/changes/archive/2026-02-17-add-opsx-onboard-skill/proposal.md ================================================ ## Why Users who run `openspec init` are left with files but no clear path to actually using the system. There's a gap between "I have OpenSpec set up" and "I understand the workflow." An onboarding skill would guide users through their first complete change cycle on a real task in their codebase, teaching the workflow by doing it. ## What Changes - Add new `/opsx:onboard` skill that guides users through their first OpenSpec change - Add corresponding slash command template for editor integrations - The skill will: - Analyze the user's codebase to suggest appropriately-scoped starter tasks - Walk through the full workflow (explore → new → proposal → specs → design → tasks → apply → archive) - Provide narration explaining each step as it happens - Result in a real, implemented change in the user's codebase ## Capabilities ### New Capabilities - `opsx-onboard-skill`: The onboarding skill that guides users through their first complete OpenSpec workflow cycle with narration and codebase-aware task suggestions ### Modified Capabilities ## Impact - `src/core/templates/skill-templates.ts`: Add `getOnboardSkillTemplate()` and `getOpsxOnboardCommandTemplate()` functions - `src/core/shared/skill-generation.ts`: Register the new skill and command templates in `getSkillTemplates()` and `getCommandTemplates()` - Users running `openspec init` or `openspec update` will get the new skill/command files generated ================================================ FILE: openspec/changes/archive/2026-02-17-add-opsx-onboard-skill/specs/opsx-onboard-skill/spec.md ================================================ ## ADDED Requirements ### Requirement: OPSX Onboard Skill The system SHALL provide an `/opsx:onboard` skill that guides users through their first complete OpenSpec workflow cycle with narration and real codebase work. #### Scenario: Skill invocation - **WHEN** user invokes `/opsx:onboard` - **THEN** agent checks if OpenSpec is initialized - **AND** if not initialized, prompts user to run `openspec init` first - **AND** if initialized, proceeds with onboarding flow #### Scenario: Welcome and expectations - **WHEN** onboarding begins - **THEN** agent displays welcome message explaining what will happen - **AND** sets expectation of ~15 minute duration - **AND** explains the workflow phases: explore → new → artifacts → apply → archive ### Requirement: Codebase Analysis for Task Suggestions The skill SHALL analyze the user's codebase to suggest appropriately-scoped starter tasks. #### Scenario: Codebase scanning - **WHEN** onboarding reaches task selection phase - **THEN** agent scans codebase for small improvement opportunities - **AND** looks for: TODO/FIXME comments, missing error handling, functions without tests, outdated dependencies, type: any in TypeScript, console.log in production code, missing input validation - **AND** checks recent git commits for context on current work #### Scenario: Task suggestion presentation - **WHEN** agent has analyzed codebase - **THEN** agent presents 3-4 specific task suggestions with scope estimates - **AND** each suggestion includes: task description, estimated scope (files/lines), why it's a good starter - **AND** offers option for user to specify their own task #### Scenario: Scope guardrail - **WHEN** user selects or describes a task that is too large - **THEN** agent gently redirects toward smaller scope - **AND** suggests breaking down or deferring the large task - **AND** offers appropriately-sized alternatives ### Requirement: Explore Phase Demo The skill SHALL briefly demonstrate explore mode before creating a change. #### Scenario: Brief explore demonstration - **WHEN** task is selected - **THEN** agent briefly demonstrates `/opsx:explore` by investigating relevant code - **AND** explains explore mode is for thinking before doing - **AND** keeps this phase short (not a full exploration session) - **AND** transitions to change creation ### Requirement: Guided Artifact Creation The skill SHALL guide users through each artifact with narration explaining the purpose. #### Scenario: Change creation with narration - **WHEN** creating the change directory - **THEN** agent runs `openspec new change ""` with derived kebab-case name - **AND** explains what a "change" is (container for thinking and planning) - **AND** shows the folder structure that was created - **AND** pauses for user acknowledgment before proceeding #### Scenario: Proposal creation with narration - **WHEN** creating proposal.md - **THEN** agent explains proposals capture WHY we're making this change - **AND** drafts proposal based on selected task - **AND** shows draft to user for approval before saving - **AND** explains the sections (Why, What Changes, Capabilities, Impact) #### Scenario: Specs creation with narration - **WHEN** creating spec files - **THEN** agent explains specs define WHAT we're building in detail - **AND** explains the requirement/scenario format - **AND** creates spec file(s) based on proposal capabilities - **AND** notes that specs become documentation that stays in sync #### Scenario: Design creation with narration - **WHEN** creating design.md - **THEN** agent explains design captures HOW we'll build it - **AND** notes this is where technical decisions and tradeoffs live - **AND** for small changes, acknowledges design may be brief - **AND** creates design based on proposal and specs #### Scenario: Tasks creation with narration - **WHEN** creating tasks.md - **THEN** agent explains tasks break work into checkboxes - **AND** explains these drive the apply phase - **AND** generates task list from design and specs - **AND** shows tasks and asks if ready to implement ### Requirement: Guided Implementation The skill SHALL implement tasks with narration connecting back to artifacts. #### Scenario: Implementation with narration - **WHEN** implementing tasks - **THEN** agent announces each task before working on it - **AND** implements the change in the codebase - **AND** occasionally references how specs/design informed decisions - **AND** marks each task complete as it finishes - **AND** keeps narration light (not over-explaining) #### Scenario: Implementation completion - **WHEN** all tasks are complete - **THEN** agent announces completion - **AND** summarizes what was done - **AND** transitions to archive phase ### Requirement: Archive with Explanation The skill SHALL archive the completed change and explain what happened. #### Scenario: Archive with narration - **WHEN** archiving the change - **THEN** agent explains archive moves change to dated folder - **AND** runs archive process - **AND** shows where archived change lives - **AND** explains the long-term value (finding decisions later) ### Requirement: Recap and Next Steps The skill SHALL conclude with a recap and command reference. #### Scenario: Final recap - **WHEN** onboarding is complete - **THEN** agent summarizes the workflow phases completed - **AND** emphasizes this rhythm works for any size change - **AND** provides command reference table (/opsx:explore, /opsx:new, /opsx:ff, /opsx:continue, /opsx:apply, /opsx:verify, /opsx:archive) - **AND** suggests next actions (try /opsx:new or /opsx:ff on something) ### Requirement: Graceful Exit Handling The skill SHALL handle users who want to stop mid-way. #### Scenario: User wants to stop - **WHEN** user indicates they want to stop during onboarding - **THEN** agent acknowledges gracefully - **AND** notes that the in-progress change is saved - **AND** explains how to continue later with `/opsx:continue ` - **AND** exits without pressure #### Scenario: User wants quick reference only - **WHEN** user says they just want to see the commands - **THEN** agent provides command cheat sheet - **AND** exits gracefully with encouragement to try `/opsx:new` ================================================ FILE: openspec/changes/archive/2026-02-17-add-opsx-onboard-skill/tasks.md ================================================ ## 1. Add Skill Template - [x] 1.1 Add `getOnboardSkillTemplate()` function to `src/core/templates/skill-templates.ts` with full onboarding instruction text covering all phases (preflight, welcome, task selection, explore demo, change creation, proposal, specs, design, tasks, apply, archive, recap) - [x] 1.2 Include codebase analysis instructions for suggesting starter tasks (TODO/FIXME, missing error handling, missing tests, type:any, console.log, missing validation) - [x] 1.3 Include narration pattern instructions (EXPLAIN → DO → SHOW → PAUSE at key transitions) - [x] 1.4 Include scope guardrail instructions for redirecting users away from overly large tasks - [x] 1.5 Include graceful exit handling instructions (user stops mid-way, user just wants command reference) ## 2. Add Command Template - [x] 2.1 Add `getOpsxOnboardCommandTemplate()` function to `src/core/templates/skill-templates.ts` returning CommandTemplate with same instruction content as skill ## 3. Register Templates - [x] 3.1 Add onboard skill to `getSkillTemplates()` array in `src/core/shared/skill-generation.ts` with dirName `openspec-onboard` - [x] 3.2 Add onboard command to `getCommandTemplates()` array in `src/core/shared/skill-generation.ts` with id `onboard` ## 4. Verify - [x] 4.1 Run `pnpm run build` to ensure TypeScript compiles - [x] 4.2 Test skill generation by running `openspec init` in a test directory and verifying onboard skill/command files are created ================================================ FILE: openspec/changes/archive/2026-02-17-add-verify-skill/design.md ================================================ # Design: Add /opsx:verify Skill ## Architecture Decision: Dynamic Generation via Setup Command ### Context All existing opsx experimental skills (explore, new, continue, apply, ff, sync, archive) are dynamically generated when users run `openspec artifact-experimental-setup`. They are not manually created files checked into the repository. ### Decision **Integrate verify into the existing artifact-experimental-setup system rather than creating static skill files.** ### Rationale 1. **Consistency**: All 7 existing opsx skills follow this pattern. Adding verify as the 8th skill should follow the same architecture. 2. **Maintainability**: Template functions in `skill-templates.ts` are the single source of truth. Changes to skill definitions automatically propagate to all users when they re-run setup. 3. **Distribution**: Users get the verify skill automatically when running `openspec artifact-experimental-setup`, just like all other opsx skills. No special installation steps needed. 4. **Versioning**: Skills are generated from the installed npm package version, ensuring consistency between CLI version and skill behavior. ### Implementation Approach #### 1. Template Functions Add two template functions to `src/core/templates/skill-templates.ts`: ```typescript export function getVerifyChangeSkillTemplate(): SkillTemplate export function getOpsxVerifyCommandTemplate(): CommandTemplate ``` These return the skill definition (for Agent Skills) and slash command definition (for explicit invocation). #### 2. Setup Integration Update `artifactExperimentalSetupCommand()` in `src/commands/artifact-workflow.ts`: - Import both template functions - Add verify to the `skills` array (position 8) - Add verify to the `commands` array (position 8) - Update help text to list `/opsx:verify` #### 3. Generated Artifacts When users run `openspec artifact-experimental-setup`, the command creates: - `.claude/skills/openspec-verify-change/SKILL.md` - Agent Skills format - `.claude/commands/opsx/verify.md` - Slash command format Both are generated from the template functions, with YAML frontmatter automatically added. ### Alternatives Considered **Alternative 1: Static skill files in repository** Create `.claude/skills/openspec-verify-change/SKILL.md` as a static file in the OpenSpec repository. **Rejected because:** - Inconsistent with all other opsx skills - Requires users to manually copy/update files - Versioning becomes complicated (repo version vs installed package version) - Breaks the established pattern **Alternative 2: Separate verify setup command** Add `openspec setup-verify` as a separate command. **Rejected because:** - Fragments the setup experience - Users would need to run multiple commands - Doesn't scale if we add more skills in the future - Goes against the "setup once, get everything" philosophy ### Trade-offs **Advantages:** - Consistent with existing architecture - Zero additional setup burden for users - Easy to update and maintain - Automatic version compatibility **Disadvantages:** - Slightly more complex initial implementation (template functions + integration) - Requires understanding the setup system (but that's already documented) ### Verification The implementation correctly follows this design if: 1. Both template functions exist in `skill-templates.ts` 2. Verify appears in both skills and commands arrays in `artifact-workflow.ts` 3. Help text mentions `/opsx:verify` 4. Running `openspec artifact-experimental-setup` generates both skill and command files 5. Build succeeds with no TypeScript errors ================================================ FILE: openspec/changes/archive/2026-02-17-add-verify-skill/proposal.md ================================================ # Change: Add /opsx:verify Skill ## Why Users need a way to validate that their implementation actually matches what was requested before archiving a change. Currently, there's no systematic way to check: - Whether all tasks are truly complete - Whether the implementation covers all spec requirements and scenarios - Whether the implementation follows the design decisions - Whether the code is coherent and makes sense A user requested: "Can we get a :verify that will ensure that the implementation matches what was requested?" ## What Changes - Add `getVerifyChangeSkillTemplate()` function to `skill-templates.ts` - Add `getOpsxVerifyCommandTemplate()` function to `skill-templates.ts` - Integrate verify skill into `artifactExperimentalSetupCommand` in `artifact-workflow.ts` - Add verify to the skills and commands arrays in the setup command - Update help text to include `/opsx:verify` in the list of available commands - Create `opsx-verify-skill` capability spec ## Verification Dimensions The skill verifies across three dimensions: 1. **Completeness** - Are all tasks done? Are all specs addressed? 2. **Correctness** - Does the implementation match specs? Are scenarios covered? 3. **Coherence** - Does the implementation make sense? Does it follow design.md? ## Output Format Produces a prioritized report with: - Summary scorecard (tasks, specs, design adherence) - Critical issues first (must fix before archive) - Warnings second (should fix) - Suggestions third (nice to have) - Actionable fix recommendations for each issue ## Impact - Affected specs: New `opsx-verify-skill` spec - Affected code: - `src/core/templates/skill-templates.ts` - Added 2 new template functions - `src/commands/artifact-workflow.ts` - Integrated verify into experimental setup - Generated artifacts: When users run `openspec artifact-experimental-setup`: - Creates `.claude/skills/openspec-verify-change/SKILL.md` - Creates `.claude/commands/opsx/verify.md` - Related skills: Works alongside `/opsx:apply` and before `/opsx:archive` ================================================ FILE: openspec/changes/archive/2026-02-17-add-verify-skill/specs/opsx-verify-skill/spec.md ================================================ # opsx-verify-skill Specification ## Purpose Defines the agent skill for verifying that implementation matches change artifacts (specs, tasks, design). ## ADDED Requirements ### Requirement: Verify Skill Invocation The system SHALL provide an `/opsx:verify` skill that validates implementation against change artifacts. #### Scenario: Verify with change name provided - **WHEN** agent executes `/opsx:verify ` - **THEN** the agent verifies implementation for that specific change - **AND** produces a verification report #### Scenario: Verify without change name - **WHEN** agent executes `/opsx:verify` without a change name - **THEN** the agent prompts user to select from available changes - **AND** shows only changes that have implementation tasks #### Scenario: Change has no tasks - **WHEN** selected change has no tasks.md or tasks are empty - **THEN** the agent reports "No tasks to verify" - **AND** suggests running `/opsx:continue` to create tasks ### Requirement: Completeness Verification The agent SHALL verify that all required work has been completed. #### Scenario: Task completion check - **WHEN** verifying completeness - **THEN** the agent reads tasks.md - **AND** counts tasks marked `- [x]` (complete) vs `- [ ]` (incomplete) - **AND** reports completion status with specific incomplete tasks listed #### Scenario: Spec coverage check - **WHEN** verifying completeness - **AND** delta specs exist in `openspec/changes//specs/` - **THEN** the agent extracts all requirements from delta specs - **AND** searches codebase for implementation of each requirement - **AND** reports which requirements appear to have implementation vs which are missing #### Scenario: All tasks complete - **WHEN** all tasks are marked complete - **THEN** report "Tasks: N/N complete" - **AND** mark completeness dimension as passed #### Scenario: Incomplete tasks found - **WHEN** some tasks are incomplete - **THEN** report "Tasks: X/N complete" - **AND** list each incomplete task - **AND** mark as CRITICAL issue - **AND** suggest: "Complete remaining tasks or mark as done if already implemented" ### Requirement: Correctness Verification The agent SHALL verify that implementation matches the specifications. #### Scenario: Requirement implementation mapping - **WHEN** verifying correctness - **THEN** for each requirement in delta specs: - Search codebase for implementation - Identify relevant files and line numbers - Assess whether implementation satisfies the requirement #### Scenario: Scenario coverage check - **WHEN** verifying correctness - **THEN** for each scenario in delta specs: - Check if the scenario's conditions are handled in code - Check if tests exist that cover the scenario - Report coverage status #### Scenario: Implementation matches spec - **WHEN** implementation appears to satisfy a requirement - **THEN** report which files/lines implement it - **AND** mark requirement as covered #### Scenario: Implementation diverges from spec - **WHEN** implementation exists but doesn't match spec intent - **THEN** report the divergence as WARNING - **AND** explain what differs - **AND** suggest: either update implementation or update spec to match reality #### Scenario: Missing implementation - **WHEN** no implementation found for a requirement - **THEN** report as CRITICAL issue - **AND** suggest: "Implement requirement X" with guidance on what's needed ### Requirement: Coherence Verification The agent SHALL verify that implementation is sensible and follows design decisions. #### Scenario: Design.md adherence check - **WHEN** verifying coherence - **AND** design.md exists for the change - **THEN** extract key decisions from design.md - **AND** verify implementation follows those decisions - **AND** report any deviations #### Scenario: No design.md - **WHEN** verifying coherence - **AND** no design.md exists - **THEN** skip design adherence check - **AND** note "No design.md to verify against" #### Scenario: Design decision followed - **WHEN** implementation follows a design decision - **THEN** report as confirmed - **AND** cite evidence from code #### Scenario: Design decision violated - **WHEN** implementation contradicts a design decision - **THEN** report as WARNING - **AND** explain the contradiction - **AND** suggest: either update implementation or update design.md #### Scenario: Code pattern consistency - **WHEN** verifying coherence - **THEN** check if new code follows existing project patterns - **AND** flag any significant deviations as suggestions ### Requirement: Verification Report Format The agent SHALL produce a structured, prioritized report. #### Scenario: Report summary - **WHEN** verification completes - **THEN** display summary scorecard: ``` ## Verification Report: ### Summary | Dimension | Status | |--------------|----------| | Completeness | X/Y | | Correctness | X/Y | | Coherence | Followed | ``` #### Scenario: Issue prioritization - **WHEN** issues are found - **THEN** group and display in priority order: 1. CRITICAL - Must fix before archive (missing implementation, incomplete tasks) 2. WARNING - Should fix (divergence from spec/design, missing tests) 3. SUGGESTION - Nice to fix (pattern inconsistencies, minor improvements) #### Scenario: Actionable recommendations - **WHEN** reporting an issue - **THEN** include specific, actionable fix recommendation - **AND** reference relevant files and line numbers where applicable - **AND** avoid vague suggestions like "consider reviewing" #### Scenario: All checks pass - **WHEN** no issues found across all dimensions - **THEN** display: ``` All checks passed. Ready for archive. ``` #### Scenario: Critical issues found - **WHEN** CRITICAL issues exist - **THEN** display: ``` X critical issue(s) found. Fix before archiving. ``` - **AND** do NOT suggest running archive #### Scenario: Only warnings/suggestions - **WHEN** no CRITICAL issues but warnings exist - **THEN** display: ``` No critical issues. Y warning(s) to consider. Ready for archive (with noted improvements). ``` ### Requirement: Flexible Artifact Handling The agent SHALL gracefully handle changes with varying artifact completeness. #### Scenario: Minimal change (tasks only) - **WHEN** change has only tasks.md - **THEN** verify task completion only - **AND** skip spec and design checks - **AND** note which checks were skipped #### Scenario: Change with specs but no design - **WHEN** change has tasks.md and delta specs but no design.md - **THEN** verify completeness and correctness - **AND** skip design adherence - **AND** still check code coherence against project patterns #### Scenario: Full change (all artifacts) - **WHEN** change has proposal, design, specs, and tasks - **THEN** perform all verification checks - **AND** cross-reference artifacts for consistency ================================================ FILE: openspec/changes/archive/2026-02-17-add-verify-skill/tasks.md ================================================ # Tasks: Add /opsx:verify Skill ## 1. Skill Template Functions - [x] 1.1 Add `getVerifyChangeSkillTemplate()` to skill-templates.ts - [x] 1.2 Add `getOpsxVerifyCommandTemplate()` to skill-templates.ts ## 2. Integration with artifact-experimental-setup - [x] 2.1 Import verify template functions in artifact-workflow.ts - [x] 2.2 Add verify to skills array in artifactExperimentalSetupCommand - [x] 2.3 Add verify to commands array in artifactExperimentalSetupCommand - [x] 2.4 Add verify to help text output ## 3. Verification (Build & Test) - [x] 3.1 Verify TypeScript compilation succeeds - [x] 3.2 Verify all 8 skills are now included (was 7, now 8) ================================================ FILE: openspec/changes/archive/2026-02-17-merge-init-experimental/.openspec.yaml ================================================ schema: spec-driven created: 2026-01-23 ================================================ FILE: openspec/changes/archive/2026-02-17-merge-init-experimental/design.md ================================================ ## Context Currently `openspec init` and `openspec experimental` are separate commands with distinct purposes: - **init**: Creates `openspec/` directory, generates `AGENTS.md`/`project.md`, configures tool config files (`CLAUDE.md`, etc.), generates old slash commands (`/openspec:proposal`, etc.) - **experimental**: Generates skills (9 per tool), generates opsx slash commands (`/opsx:new`, etc.), creates `config.yaml` The skill-based workflow (experimental) is the direction we're going, so we're making it the default by merging into `init`. ## Goals / Non-Goals **Goals:** - Single `openspec init` command that sets up the complete skill-based workflow - Clean migration path for existing users with legacy artifacts - Remove all code related to config files and old slash commands - Keep the polished UX from experimental (animated welcome, searchable multi-select) **Non-Goals:** - Supporting both workflows simultaneously - Providing options to use the old workflow - Backward compatibility for `/openspec:*` commands (breaking change) ## Decisions ### Decision 1: Merge into init, not into experimental **Choice**: Rewrite `init` to do what `experimental` does, then delete `experimental`. **Rationale**: `init` is the canonical setup command. Users expect `init` to set up their project. `experimental` was always meant to be temporary. **Alternatives considered**: - Keep `experimental` as the main command → confusing name for default behavior - Create new command → unnecessary, `init` already exists ### Decision 2: Legacy cleanup with Y/N prompt **Choice**: Detect legacy artifacts, show what was found, prompt `"Legacy files detected. Upgrade and clean up? [Y/n]"`, then remove if confirmed. **Rationale**: Users should know what's being removed. A single Y/N is simple and decisive. No need for multiple options. **Alternatives considered**: - Multiple options (keep/remove/cancel) → overcomplicated - Silent removal → users might be surprised - Just warn without removing → leaves cruft ### Decision 3: Surgical removal of legacy content **Choice**: For files with mixed content (OpenSpec markers + user content), only remove the OpenSpec marker block. For files that are 100% OpenSpec content, delete the entire file. **Rationale**: Respects user customizations. CLAUDE.md might have other instructions beyond OpenSpec. **Edge cases**: - **Config files with mixed content**: Remove only `` to `` block - **Config files that are 100% OpenSpec**: Delete file entirely (check if content outside markers is empty/whitespace) - **Old slash command directories** (`.claude/commands/openspec/`): Delete entire directory (ours) - **`openspec/AGENTS.md`**: Delete (ours) - **Root `AGENTS.md`**: Only remove OpenSpec marker block, preserve rest ### Decision 6: Preserve project.md with migration hint **Choice**: Do NOT auto-delete `openspec/project.md`. Preserve it and show a message directing users to manually migrate content to `config.yaml`'s `context:` field. **Rationale**: - `project.md` may contain valuable user-written project documentation - The new workflow uses `config.yaml.context` for the same purpose (auto-injected into artifacts) - Auto-deleting would lose user content; auto-migrating is complex (needs LLM to compress) - Users can migrate manually or use `/opsx:explore` to get AI assistance **Migration path**: 1. During legacy cleanup, detect `openspec/project.md` but do not delete 2. Show in output: "openspec/project.md still exists - migrate content to config.yaml's context: field, then delete" 3. User migrates manually or asks Claude in explore mode: "help me migrate project.md to config.yaml" 4. User deletes project.md when ready **Why not auto-migrate?** - `project.md` is verbose (sections, headers, placeholders) - `config.yaml.context` should be concise and dense - LLM compression would be ideal but adds complexity and non-determinism to init - Manual migration lets users decide what's actually important ### Decision 4: Hidden alias for experimental **Choice**: Keep `openspec experimental` as a hidden command that delegates to `init`. **Rationale**: Users who learned `experimental` can still use it during transition. Hidden means it won't show in help. ### Decision 5: Reuse existing infrastructure **Choice**: Reuse skill templates, command adapters, welcome screen, and multi-select from experimental. **Rationale**: Already built and working. Just needs to be called from init instead of experimental. ## Risks / Trade-offs | Risk | Mitigation | |------|------------| | Users with custom `/openspec:*` commands lose them | Document in release notes; old commands are in git history | | Mixed-content detection might be imperfect | Conservative approach: if unsure, preserve the file and warn | | Users confused by missing config files | Clear messaging in init output about what changed | | `openspec update` might break | Review and update `update` command to work with new structure | ## Architecture ### What init creates (after merge) ``` openspec/ ├── config.yaml # Schema settings (from experimental) ├── specs/ # Empty, for user's specs └── changes/ # Empty, for user's changes └── archive/ ./skills/ # 9 skills per selected tool ├── openspec-explore/SKILL.md ├── openspec-new-change/SKILL.md ├── openspec-continue-change/SKILL.md ├── openspec-apply-change/SKILL.md ├── openspec-ff-change/SKILL.md ├── openspec-verify-change/SKILL.md ├── openspec-sync-specs/SKILL.md ├── openspec-archive-change/SKILL.md └── openspec-bulk-archive-change/SKILL.md ./commands/opsx/ # 9 slash commands per selected tool ├── explore.md ├── new.md ├── continue.md ├── apply.md ├── ff.md ├── verify.md ├── sync.md ├── archive.md └── bulk-archive.md ``` ### What init no longer creates - `CLAUDE.md`, `.cursorrules`, `.windsurfrules`, etc. (config files) - `openspec/AGENTS.md` - `openspec/project.md` - Root `AGENTS.md` stub - `.claude/commands/openspec/` (old slash commands) ### Legacy detection targets | Artifact Type | Detection Method | Removal Method | |--------------|------------------|----------------| | Config files (CLAUDE.md, etc.) | File exists AND contains OpenSpec markers | Remove marker block; delete file if empty after | | Old slash command dirs | Directory exists at `./commands/openspec/` | Delete entire directory | | openspec/AGENTS.md | File exists at `openspec/AGENTS.md` | Delete file | | openspec/project.md | File exists at `openspec/project.md` | **Preserve** - show migration hint only | | Root AGENTS.md | File exists at `AGENTS.md` AND contains OpenSpec markers | Remove marker block; delete file if empty after | ### Code to remove - `src/core/configurators/` - entire directory (ToolRegistry, all config generators) - `src/core/configurators/slash/` - entire directory (SlashCommandRegistry, old command generators) - `src/core/templates/slash-command-templates.ts` - old `/openspec:*` content - `src/core/templates/claude-template.ts` - `src/core/templates/cline-template.ts` - `src/core/templates/costrict-template.ts` - `src/core/templates/agents-template.ts` - `src/core/templates/agents-root-stub.ts` - `src/core/templates/project-template.ts` - `src/commands/experimental/` - entire directory (merged into init) - Related test files ### Code to migrate into init - Animated welcome screen (`src/ui/welcome-screen.ts`) - keep, call from init - Searchable multi-select (`src/prompts/searchable-multi-select.ts`) - keep, call from init - Skill templates (`src/core/templates/skill-templates.ts`) - keep - Command generation (`src/core/command-generation/`) - keep - Tool states detection (from `experimental/setup.ts`) - move to init ## Open Questions 1. **What happens to `openspec update`?** - RESOLVED **Current behavior**: Updates `openspec/AGENTS.md`, config files (`CLAUDE.md`, etc.) via `ToolRegistry`, and old slash commands (`/openspec:*`) via `SlashCommandRegistry`. **New behavior**: Rewrite to refresh skills and opsx commands instead: - Detect which tools have skills installed (check for `.claude/skills/openspec-*/`, etc.) - Refresh all 9 skill files per installed tool using `skill-templates.ts` - Refresh all 9 opsx command files per installed tool using `command-generation/` adapters - Remove imports of `ToolRegistry`, `SlashCommandRegistry`, `agentsTemplate` - Update output messaging to reflect skills/commands instead of config files **Key principle**: Same as current update - only refresh existing tools, don't add new ones. 2. **Should we keep `openspec schemas` and other experimental subcommands?** - RESOLVED **Decision**: Yes, keep them. Remove "[Experimental]" label from all subcommands (status, instructions, schemas, etc.). See task 4.3. ================================================ FILE: openspec/changes/archive/2026-02-17-merge-init-experimental/proposal.md ================================================ ## Why The current setup has two separate commands (`openspec init` and `openspec experimental`) that configure different parts of the OpenSpec workflow. This creates confusion about which command to run, results in partial setups, and maintains two parallel systems (config files + old slash commands vs skills + opsx commands). Making the skill-based workflow the default simplifies onboarding and establishes a single, consistent way to use OpenSpec. ## What Changes - **BREAKING**: `openspec init` now generates skills and `/opsx:*` commands instead of config files and `/openspec:*` commands - **BREAKING**: Config files (`CLAUDE.md`, `.cursorrules`, etc.) are no longer generated - **BREAKING**: Old slash commands (`/openspec:proposal`, `/openspec:apply`, `/openspec:archive`) are no longer generated - **BREAKING**: `openspec/AGENTS.md` and `openspec/project.md` are no longer generated - Merge `experimental` command functionality into `init` - Add legacy detection and auto-cleanup with Y/N confirmation - Keep `openspec experimental` as hidden alias for backward compatibility - Use the animated welcome screen from experimental for the unified init ## Capabilities ### New Capabilities - `legacy-cleanup`: Detect and remove legacy OpenSpec artifacts (config files, old slash commands, AGENTS.md) during init ### Modified Capabilities - `cli-init`: Complete rewrite - generates skills and opsx commands instead of config files and old slash commands; removes AGENTS.md/project.md generation; adds legacy cleanup; uses experimental's animated welcome screen ## Impact - **Code removal**: `ToolRegistry`, `SlashCommandRegistry`, config file generators, old slash command templates, AGENTS.md/project.md templates - **Code migration**: Move skill generation and command adapter logic from `experimental/setup.ts` into `init.ts` - **Commands affected**: `init` (rewritten), `experimental` (becomes hidden alias), `update` (may need adjustment) - **User migration**: Existing users running `init` will be prompted to clean up legacy files - **Breaking for**: Users relying on config files for passive triggering, users using `/openspec:*` commands ================================================ FILE: openspec/changes/archive/2026-02-17-merge-init-experimental/specs/cli-init/spec.md ================================================ ## MODIFIED Requirements ### Requirement: Directory Creation The command SHALL create the OpenSpec directory structure with config file. #### Scenario: Creating OpenSpec structure - **WHEN** `openspec init` is executed - **THEN** create the following directory structure: ``` openspec/ ├── config.yaml ├── specs/ └── changes/ └── archive/ ``` ### Requirement: AI Tool Configuration The command SHALL configure AI coding assistants with skills and slash commands using a searchable multi-select experience. #### Scenario: Prompting for AI tool selection - **WHEN** run interactively - **THEN** display animated welcome screen with OpenSpec logo - **AND** present a searchable multi-select that shows all available tools - **AND** mark already configured tools with "(configured ✓)" indicator - **AND** pre-select configured tools for easy refresh - **AND** sort configured tools to appear first in the list - **AND** allow filtering by typing to search #### Scenario: Selecting tools to configure - **WHEN** user selects tools and confirms - **THEN** generate skills in `./skills/` directory for each selected tool - **AND** generate slash commands in `./commands/opsx/` directory for each selected tool - **AND** create `openspec/config.yaml` with default schema setting ### Requirement: Skill Generation The command SHALL generate Agent Skills for selected AI tools. #### Scenario: Generating skills for a tool - **WHEN** a tool is selected during initialization - **THEN** create 9 skill directories under `./skills/`: - `openspec-explore/SKILL.md` - `openspec-new-change/SKILL.md` - `openspec-continue-change/SKILL.md` - `openspec-apply-change/SKILL.md` - `openspec-ff-change/SKILL.md` - `openspec-verify-change/SKILL.md` - `openspec-sync-specs/SKILL.md` - `openspec-archive-change/SKILL.md` - `openspec-bulk-archive-change/SKILL.md` - **AND** each SKILL.md SHALL contain YAML frontmatter with name and description - **AND** each SKILL.md SHALL contain the skill instructions ### Requirement: Slash Command Generation The command SHALL generate opsx slash commands for selected AI tools. #### Scenario: Generating slash commands for a tool - **WHEN** a tool is selected during initialization - **THEN** create 9 slash command files using the tool's command adapter: - `/opsx:explore` - `/opsx:new` - `/opsx:continue` - `/opsx:apply` - `/opsx:ff` - `/opsx:verify` - `/opsx:sync` - `/opsx:archive` - `/opsx:bulk-archive` - **AND** use tool-specific path conventions (e.g., `.claude/commands/opsx/` for Claude) - **AND** include tool-specific frontmatter format ### Requirement: Success Output The command SHALL provide clear, actionable next steps upon successful initialization. #### Scenario: Displaying success message - **WHEN** initialization completes successfully - **THEN** display categorized summary: - "Created: " for newly configured tools - "Refreshed: " for already-configured tools that were updated - Count of skills and commands generated - **AND** display getting started section with: - `/opsx:new` - Start a new change - `/opsx:continue` - Create the next artifact - `/opsx:apply` - Implement tasks - **AND** display links to documentation and feedback #### Scenario: Displaying restart instruction - **WHEN** initialization completes successfully and tools were created or refreshed - **THEN** display instruction to restart IDE for slash commands to take effect ### Requirement: Config File Generation The command SHALL create an OpenSpec config file with schema settings. #### Scenario: Creating config.yaml - **WHEN** initialization completes - **AND** config.yaml does not exist - **THEN** create `openspec/config.yaml` with default schema setting - **AND** display config location in output #### Scenario: Preserving existing config.yaml - **WHEN** initialization runs in extend mode - **AND** `openspec/config.yaml` already exists - **THEN** preserve the existing config file - **AND** display "(exists)" indicator in output ### Requirement: Non-Interactive Mode The command SHALL support non-interactive operation through command-line options. #### Scenario: Select all tools non-interactively - **WHEN** run with `--tools all` - **THEN** automatically select every available AI tool without prompting - **AND** proceed with skill and command generation #### Scenario: Select specific tools non-interactively - **WHEN** run with `--tools claude,cursor` - **THEN** parse the comma-separated tool IDs - **AND** generate skills and commands for specified tools only #### Scenario: Skip tool configuration non-interactively - **WHEN** run with `--tools none` - **THEN** create only the openspec directory structure and config.yaml - **AND** skip skill and command generation ### Requirement: Experimental Command Alias The command SHALL maintain backward compatibility with the experimental command. #### Scenario: Running openspec experimental - **WHEN** user runs `openspec experimental` - **THEN** delegate to `openspec init` - **AND** the command SHALL be hidden from help output ## REMOVED Requirements ### Requirement: File Generation **Reason**: AGENTS.md and project.md are no longer generated. Skills contain all necessary instructions. **Migration**: Skills in `./skills/` provide all OpenSpec workflow instructions. No manual file needed. ### Requirement: AI Tool Configuration Details **Reason**: Config files (CLAUDE.md, .cursorrules, etc.) are replaced by skills. **Migration**: Use skills in `./skills/` instead of config files. Skills provide richer, tool-specific instructions. ### Requirement: Slash Command Configuration **Reason**: Old `/openspec:*` slash commands are replaced by `/opsx:*` commands with richer functionality. **Migration**: Use `/opsx:new`, `/opsx:continue`, `/opsx:apply` instead of `/openspec:proposal`, `/openspec:apply`, `/openspec:archive`. ### Requirement: Root instruction stub **Reason**: Root AGENTS.md stub is no longer needed. Skills provide tool-specific instructions. **Migration**: Skills are loaded automatically by supporting tools. No root stub needed. ================================================ FILE: openspec/changes/archive/2026-02-17-merge-init-experimental/specs/legacy-cleanup/spec.md ================================================ ## ADDED Requirements ### Requirement: Legacy artifact detection The system SHALL detect legacy OpenSpec artifacts from previous init versions. #### Scenario: Detecting legacy config files - **WHEN** running `openspec init` on an existing project - **THEN** the system SHALL check for config files with OpenSpec markers: - `CLAUDE.md` - `.cursorrules` - `.windsurfrules` - `.clinerules` - `.kilocode_rules` - `.github/copilot-instructions.md` - `.amazonq/instructions.md` - `CODEBUDDY.md` - `IFLOW.md` - And all other tool config files from the legacy ToolRegistry #### Scenario: Detecting legacy slash command directories - **WHEN** running `openspec init` on an existing project - **THEN** the system SHALL check for old slash command directories: - `.claude/commands/openspec/` - `.cursor/commands/openspec/` (note: old format used `openspec-*.md` in commands root) - `.windsurf/workflows/openspec-*.md` - And equivalent directories for all tools in the legacy SlashCommandRegistry #### Scenario: Detecting legacy OpenSpec structure files - **WHEN** running `openspec init` on an existing project - **THEN** the system SHALL check for: - `openspec/AGENTS.md` - `openspec/project.md` (for migration messaging only, not deleted) - Root `AGENTS.md` with OpenSpec markers ### Requirement: Legacy cleanup confirmation The system SHALL prompt for confirmation before removing legacy artifacts. #### Scenario: Prompting for cleanup when legacy detected - **WHEN** legacy artifacts are detected - **THEN** the system SHALL display what was found - **AND** prompt: "Legacy files detected. Upgrade and clean up? [Y/n]" - **AND** default to Yes if user presses Enter #### Scenario: User confirms cleanup - **WHEN** user responds Y or presses Enter - **THEN** the system SHALL remove legacy artifacts - **AND** proceed with skill-based setup #### Scenario: User declines cleanup - **WHEN** user responds N - **THEN** the system SHALL abort initialization - **AND** display message suggesting manual cleanup or using `--force` flag #### Scenario: Non-interactive mode - **WHEN** running with `--no-interactive` or in CI environment - **AND** legacy artifacts are detected - **THEN** the system SHALL abort with exit code 1 - **AND** display detected legacy artifacts - **AND** suggest running interactively or using `--force` flag ### Requirement: Surgical removal of config file content The system SHALL preserve user content when removing OpenSpec markers from config files. #### Scenario: Config file with only OpenSpec content - **WHEN** a config file contains only OpenSpec marker block (whitespace outside is acceptable) - **THEN** the system SHALL remove the OpenSpec marker block - **AND** preserve the file (even if empty or whitespace-only) - **AND** NOT delete the file (config files belong to the user's project root) #### Scenario: Config file with mixed content - **WHEN** a config file contains content outside OpenSpec markers - **THEN** the system SHALL remove only the `` to `` block - **AND** preserve all content before and after the markers - **AND** clean up any resulting double blank lines #### Scenario: Root AGENTS.md with mixed content - **WHEN** root `AGENTS.md` contains OpenSpec markers AND other content - **THEN** the system SHALL remove only the OpenSpec marker block - **AND** preserve the rest of the file ### Requirement: Legacy directory removal The system SHALL remove legacy slash command directories entirely. #### Scenario: Removing old slash command directory - **WHEN** a legacy slash command directory exists (e.g., `.claude/commands/openspec/`) - **THEN** the system SHALL delete the entire directory and its contents - **AND** NOT delete the parent directory (e.g., `.claude/commands/` remains) #### Scenario: Removing legacy AGENTS.md - **WHEN** `openspec/AGENTS.md` exists - **THEN** the system SHALL delete the file - **AND** NOT delete the `openspec/` directory itself ### Requirement: project.md migration hint The system SHALL preserve project.md and display a migration hint instead of deleting it. #### Scenario: project.md exists during upgrade - **WHEN** `openspec/project.md` exists during legacy cleanup - **THEN** the system SHALL NOT delete the file - **AND** the system SHALL display a migration hint in the output: ``` Manual migration needed: → openspec/project.md still exists Move useful content to config.yaml's "context:" field, then delete ``` #### Scenario: project.md migration rationale - **GIVEN** project.md may contain user-written project documentation - **AND** config.yaml's context field serves the same purpose (auto-injected into artifacts) - **WHEN** displaying the migration hint - **THEN** users can migrate manually or use `/opsx:explore` to get AI assistance ### Requirement: Cleanup reporting The system SHALL report what was cleaned up. #### Scenario: Displaying cleanup summary - **WHEN** legacy cleanup completes - **THEN** the system SHALL display a summary section: ``` Cleaned up legacy files: ✓ Removed OpenSpec markers from CLAUDE.md ✓ Removed .claude/commands/openspec/ (replaced by /opsx:*) ✓ Removed openspec/AGENTS.md (no longer needed) ``` - **AND IF** `openspec/project.md` exists - **THEN** the system SHALL display a separate migration section: ``` Manual migration needed: → openspec/project.md still exists Move useful content to config.yaml's "context:" field, then delete ``` #### Scenario: No legacy detected - **WHEN** no legacy artifacts are found - **THEN** the system SHALL NOT display the cleanup section - **AND** proceed directly with skill setup ================================================ FILE: openspec/changes/archive/2026-02-17-merge-init-experimental/tasks.md ================================================ ## 1. Legacy Detection & Cleanup Module - [x] 1.1 Create `src/core/legacy-cleanup.ts` with detection functions for all legacy artifact types - [x] 1.2 Implement `detectLegacyConfigFiles()` - check for config files with OpenSpec markers - [x] 1.3 Implement `detectLegacySlashCommands()` - check for old `/openspec:*` command directories - [x] 1.4 Implement `detectLegacyStructureFiles()` - check for AGENTS.md (project.md detected separately for messaging) - [x] 1.5 Implement `removeMarkerBlock()` - surgically remove OpenSpec marker blocks from files - [x] 1.6 Implement `cleanupLegacyArtifacts()` - orchestrate removal with proper edge case handling (preserves project.md) - [x] 1.7 Implement migration hint output for project.md - show message directing users to migrate to config.yaml - [x] 1.8 Add unit tests for legacy detection and cleanup functions ## 2. Rewrite Init Command - [x] 2.1 Replace `src/core/init.ts` with new implementation using experimental's approach - [x] 2.2 Import and use animated welcome screen from `src/ui/welcome-screen.ts` - [x] 2.3 Import and use searchable multi-select from `src/prompts/searchable-multi-select.ts` - [x] 2.4 Integrate legacy detection at start of init flow - [x] 2.5 Add Y/N prompt for legacy cleanup confirmation - [x] 2.6 Generate skills using existing `skill-templates.ts` - [x] 2.7 Generate slash commands using existing `command-generation/` adapters - [x] 2.8 Create `openspec/config.yaml` with default schema - [x] 2.9 Update success output to match new workflow (skills, /opsx:* commands) - [x] 2.10 Add `--force` flag to skip legacy cleanup prompt in non-interactive mode ## 3. Remove Legacy Code - [x] 3.1 Delete `src/core/configurators/` directory (ToolRegistry, all config generators) - [x] 3.2 Delete `src/core/templates/slash-command-templates.ts` - [x] 3.3 Delete `src/core/templates/claude-template.ts` - [x] 3.4 Delete `src/core/templates/cline-template.ts` - [x] 3.5 Delete `src/core/templates/costrict-template.ts` - [x] 3.6 Delete `src/core/templates/agents-template.ts` - [x] 3.7 Delete `src/core/templates/agents-root-stub.ts` - [x] 3.8 Delete `src/core/templates/project-template.ts` - [x] 3.9 Delete `src/commands/experimental/` directory - [x] 3.10 Update `src/core/templates/index.ts` to remove deleted exports - [x] 3.11 Delete related test files for removed modules (wizard.ts) ## 4. Update CLI Registration - [x] 4.1 Update `src/cli/index.ts` to remove `registerArtifactWorkflowCommands()` call - [x] 4.2 Keep experimental subcommands (status, instructions, schemas, etc.) but register directly - [x] 4.3 Remove "[Experimental]" labels from kept subcommands - [x] 4.4 Add hidden `experimental` command as alias to `init` ## 5. Update Related Commands - [x] 5.1 Update `openspec update` command to refresh skills/commands instead of config files - [x] 5.2 Remove config file refresh logic from update - [x] 5.3 Add skill refresh logic to update ## 6. Testing & Verification - [x] 6.1 Add integration tests for new init flow (fresh install) - [x] 6.2 Add integration tests for legacy detection and cleanup - [x] 6.3 Add integration tests for extend mode (re-running init) - [x] 6.4 Test non-interactive mode with `--tools` flag - [x] 6.5 Test `--force` flag for CI environments - [x] 6.6 Verify cross-platform path handling (use path.join throughout) - [x] 6.7 Run full test suite and fix any broken tests ## 7. Documentation & Cleanup - [x] 7.1 Update README with new init behavior (skill-based workflow is self-documenting) - [x] 7.2 Document breaking changes for release notes (in tasks file) - [x] 7.3 Remove any orphaned imports/references to deleted modules (verified none exist) - [x] 7.4 Run linter and fix any issues (passed) ================================================ FILE: openspec/changes/archive/2026-02-17-multi-provider-skill-generation/.openspec.yaml ================================================ schema: spec-driven created: 2026-01-22 ================================================ FILE: openspec/changes/archive/2026-02-17-multi-provider-skill-generation/design.md ================================================ ## Context The `artifact-experimental-setup` command generates skill files and opsx slash commands for AI coding assistants. Currently it hardcodes paths to `.claude/skills` and `.claude/commands/opsx`. The existing `AI_TOOLS` array in `config.ts` lists 22 AI tools but lacks path information. There's also an existing `SlashCommandConfigurator` system for the old workflow commands, but it's tightly coupled to the old 3 commands (proposal, apply, archive) and can't be easily extended for the 9 opsx commands. Each AI tool has: - Different skill directory conventions (`.claude/skills/`, `.cursor/skills/`, etc.) - Different command file paths (`.claude/commands/opsx/`, `.cursor/commands/`, etc.) - Different frontmatter formats (YAML keys, structure varies by tool) ## Goals / Non-Goals **Goals:** - Support skill generation for any AI tool following the Agent Skills spec - Support command generation with tool-specific formatting via adapters - Require explicit tool selection (no defaults) - Create a generic, extensible command generation system **Non-Goals:** - Global path installation for tools other than Codex (Codex uses absolute adapter paths today) - Multi-tool generation in single command (future enhancement) - Unifying with existing SlashCommandConfigurator (separate systems for now) ## Decisions ### 1. Add `skillsDir` to `AIToolOption` interface **Decision**: Add single `skillsDir` field to existing interface. No `commandsDir` or `globalSkillsDir`. ```typescript interface AIToolOption { name: string; value: string; available: boolean; successLabel?: string; skillsDir?: string; // e.g., '.claude' - /skills suffix per Agent Skills spec } ``` **Rationale**: - Skills follow Agent Skills spec: `/skills/` - suffix is standard - Commands need per-tool formatting, handled by adapters (not a simple path) - Global paths supported — Codex adapter returns absolute paths via os.homedir() ### 2. Strategy/Adapter pattern for command generation **Decision**: Create generic command generation with tool-specific adapters. ```text ┌─────────────────────────────────────────────────────────────────┐ │ CommandContent │ │ (tool-agnostic: id, name, description, category, tags, body) │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ generateCommand(content, adapter) │ └─────────────────────────────────────────────────────────────────┘ │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Claude │ │ Cursor │ │ Windsurf │ │ Adapter │ │ Adapter │ │ Adapter │ └──────────┘ └──────────┘ └──────────┘ ``` **Interfaces:** ```typescript // Tool-agnostic command data interface CommandContent { id: string; // e.g., 'explore', 'new', 'apply' name: string; // e.g., 'OpenSpec Explore' description: string; // e.g., 'Enter explore mode...' category: string; // e.g., 'OpenSpec' tags: string[]; // e.g., ['openspec', 'explore'] body: string; // The command instructions } // Per-tool formatting strategy interface ToolCommandAdapter { toolId: string; getFilePath(commandId: string): string; formatFile(content: CommandContent): string; } ``` **Rationale**: - Separates "what to generate" from "how to format it" - Each tool's frontmatter quirks encapsulated in its adapter - Easy to add new tools by implementing adapter interface - Body content shared across all tools **Alternative considered**: Extend existing SlashCommandConfigurator - Rejected: Tightly coupled to old 3 commands, significant refactor needed ### 3. Adapter registry pattern **Decision**: Create `CommandAdapterRegistry` similar to existing `SlashCommandRegistry`. ```typescript class CommandAdapterRegistry { private static adapters: Map = new Map(); static get(toolId: string): ToolCommandAdapter | undefined; static getAll(): ToolCommandAdapter[]; } ``` **Rationale**: - Consistent with existing codebase patterns - Easy lookup by tool ID - Centralized registration ### 4. Required tool flag **Decision**: Require `--tool` flag - error if omitted. **Rationale**: - Explicit tool selection avoids assumptions - Consistent with project convention of not providing defaults - Users must consciously choose their target tool ## Risks / Trade-offs **[Risk] Adapter maintenance burden** → Each new tool needs an adapter. Mitigated by simple interface - most adapters are ~20 lines. **[Risk] Frontmatter format drift** → Tools may change their formats. Mitigated by encapsulating format in adapter - single place to update. **[Trade-off] Two command systems** → Old SlashCommandConfigurator and new CommandAdapterRegistry coexist. Acceptable for now - can unify later if needed. **[Trade-off] skillsDir optional** → Tools without skillsDir configured will error. Acceptable - we add paths as tools are tested. ## Implementation Approach 1. Add `skillsDir` to `AIToolOption` and populate for known tools 2. Create `CommandContent` and `ToolCommandAdapter` interfaces 3. Implement adapters for Claude, Cursor, Windsurf (start with 3) 4. Create `CommandAdapterRegistry` 5. Create `generateCommand()` function 6. Update `artifact-experimental-setup` to use new system 7. Add `--tool` flag with validation ================================================ FILE: openspec/changes/archive/2026-02-17-multi-provider-skill-generation/proposal.md ================================================ ## Why The `artifact-experimental-setup` command currently hardcodes skill output paths to `.claude/skills` and `.claude/commands/opsx`. This prevents users of other AI coding tools (Cursor, Windsurf, Codex, etc.) from using OpenSpec's skill generation. We need to support the diverse ecosystem of AI coding assistants, each with their own conventions for skill/instruction file locations and command frontmatter formats. ## What Changes - Add `skillsDir` path configuration to the existing `AIToolOption` interface in `config.ts` - Add required `--tool ` flag to the `artifact-experimental-setup` command - Create a generic command generation system using Strategy/Adapter pattern: - `CommandContent`: tool-agnostic command data (id, name, description, body) - `ToolCommandAdapter`: per-tool formatting (file paths, frontmatter format) - `CommandGenerator`: orchestrates generation using content + adapter - Require explicit tool selection (no default) for clarity ## Capabilities ### New Capabilities - `ai-tool-paths`: Configuration mapping AI tool IDs to their project-local skill directory paths - `command-generation`: Generic command generation system with tool adapters for formatting differences ### Modified Capabilities - `cli-artifact-workflow`: Adding `--tool` flag to setup command for provider selection ## Impact - **Files Modified**: - `src/core/config.ts` - Extend `AIToolOption` interface with `skillsDir` field - `src/commands/artifact-workflow.ts` - Add `--tool` flag, use provider paths and adapters - **New Files**: - `src/core/command-generation/types.ts` - CommandContent, ToolCommandAdapter interfaces - `src/core/command-generation/generator.ts` - Generic command generator - `src/core/command-generation/adapters/*.ts` - Per-tool adapters - **Backward Compatibility**: Existing workflows unaffected - this is a new command setup feature - **User-Facing**: Required `--tool` flag on `artifact-experimental-setup` command for explicit tool selection ================================================ FILE: openspec/changes/archive/2026-02-17-multi-provider-skill-generation/specs/ai-tool-paths/spec.md ================================================ # ai-tool-paths Specification ## Purpose Define the path configuration for AI coding tool skill directories, enabling skill generation to target different tools following the Agent Skills spec. ## Requirements ## ADDED Requirements ### Requirement: AIToolOption skillsDir field The `AIToolOption` interface SHALL include an optional `skillsDir` field for skill generation path configuration. #### Scenario: Interface includes skillsDir field - **WHEN** a tool entry is defined in `AI_TOOLS` that supports skill generation - **THEN** it SHALL include a `skillsDir` field specifying the project-local base directory (e.g., `.claude`) #### Scenario: Skills path follows Agent Skills spec - **WHEN** generating skills for a tool with `skillsDir: '.claude'` - **THEN** skills SHALL be written to `//skills/` - **AND** the `/skills` suffix is appended per Agent Skills specification ### Requirement: Path configuration for supported tools The `AI_TOOLS` array SHALL include `skillsDir` for tools that support the Agent Skills specification. #### Scenario: Claude Code paths defined - **WHEN** looking up the `claude` tool - **THEN** `skillsDir` SHALL be `.claude` #### Scenario: Cursor paths defined - **WHEN** looking up the `cursor` tool - **THEN** `skillsDir` SHALL be `.cursor` #### Scenario: Windsurf paths defined - **WHEN** looking up the `windsurf` tool - **THEN** `skillsDir` SHALL be `.windsurf` #### Scenario: Tools without skillsDir - **WHEN** a tool has no `skillsDir` defined - **THEN** skill generation SHALL error with message indicating the tool is not supported ### Requirement: Cross-platform path handling The system SHALL handle paths correctly across operating systems. #### Scenario: Path construction on Windows - **WHEN** constructing skill paths on Windows - **THEN** the system SHALL use `path.join()` for all path construction - **AND** SHALL NOT hardcode forward slashes #### Scenario: Path construction on Unix - **WHEN** constructing skill paths on macOS or Linux - **THEN** the system SHALL use `path.join()` for consistency ================================================ FILE: openspec/changes/archive/2026-02-17-multi-provider-skill-generation/specs/cli-artifact-workflow/spec.md ================================================ # cli-artifact-workflow Delta Specification ## Purpose Add `--tool` flag to the `artifact-experimental-setup` command for multi-provider support. ## ADDED Requirements ### Requirement: Tool selection flag The `artifact-experimental-setup` command SHALL accept a `--tool ` flag to specify the target AI tool. #### Scenario: Specify tool via flag - **WHEN** user runs `openspec artifact-experimental-setup --tool cursor` - **THEN** skill files are generated in `.cursor/skills/` - **AND** command files are generated using Cursor's frontmatter format #### Scenario: Missing tool flag - **WHEN** user runs `openspec artifact-experimental-setup` without `--tool` - **THEN** the system displays an error requiring the `--tool` flag - **AND** lists valid tool IDs in the error message #### Scenario: Unknown tool ID - **WHEN** user runs `openspec artifact-experimental-setup --tool unknown-tool` - **AND** the tool ID is not in `AI_TOOLS` - **THEN** the system displays an error listing valid tool IDs #### Scenario: Tool without skillsDir - **WHEN** user specifies a tool that has no `skillsDir` configured - **THEN** the system displays an error indicating skill generation is not supported for that tool #### Scenario: Tool without command adapter - **WHEN** user specifies a tool that has `skillsDir` but no command adapter registered - **THEN** skill files are generated successfully - **AND** command generation is skipped with informational message ### Requirement: Output messaging The setup command SHALL display clear output about what was generated. #### Scenario: Show target tool in output - **WHEN** setup command runs successfully - **THEN** output includes the target tool name (e.g., "Setting up for Cursor...") #### Scenario: Show generated paths - **WHEN** setup command completes - **THEN** output lists all generated skill file paths - **AND** lists all generated command file paths (if applicable) #### Scenario: Show skipped commands message - **WHEN** command generation is skipped due to missing adapter - **THEN** output includes message: "Command generation skipped - no adapter for " ================================================ FILE: openspec/changes/archive/2026-02-17-multi-provider-skill-generation/specs/command-generation/spec.md ================================================ # command-generation Specification ## Purpose Define a generic command generation system that supports multiple AI tools through a Strategy/Adapter pattern, separating command content from tool-specific formatting. ## ADDED Requirements ### Requirement: CommandContent interface The system SHALL define a tool-agnostic `CommandContent` interface for command data. #### Scenario: CommandContent structure - **WHEN** defining a command to generate - **THEN** `CommandContent` SHALL include: - `id`: string identifier (e.g., 'explore', 'apply') - `name`: human-readable name (e.g., 'OpenSpec Explore') - `description`: brief description of command purpose - `category`: grouping category (e.g., 'OpenSpec') - `tags`: array of tag strings - `body`: the command instruction content ### 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/.md` #### Scenario: Cursor adapter formatting - **WHEN** formatting a command for Cursor - **THEN** the adapter SHALL output YAML frontmatter with `name` as `/opsx-`, `id`, `category`, `description` fields - **AND** file path SHALL follow pattern `.cursor/commands/opsx-.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-.md` ### Requirement: Command generator function The system SHALL provide a `generateCommand` function that combines content with adapter. #### Scenario: Generate command file - **WHEN** calling `generateCommand(content, adapter)` - **THEN** it SHALL return an object with: - `path`: the file path from `adapter.getFilePath(content.id)` - `fileContent`: the formatted content from `adapter.formatFile(content)` #### Scenario: Generate multiple commands - **WHEN** generating all opsx commands for a tool - **THEN** the system SHALL iterate over command contents and generate each using the tool's adapter ### Requirement: CommandAdapterRegistry The system SHALL provide a registry for looking up tool adapters. #### Scenario: Get adapter by tool ID - **WHEN** calling `CommandAdapterRegistry.get('cursor')` - **THEN** it SHALL return the Cursor adapter or undefined if not registered #### Scenario: Get all adapters - **WHEN** calling `CommandAdapterRegistry.getAll()` - **THEN** it SHALL return array of all registered adapters #### Scenario: Adapter not found - **WHEN** looking up an adapter for unregistered tool - **THEN** `CommandAdapterRegistry.get()` SHALL return undefined - **AND** caller SHALL handle missing adapter appropriately ### Requirement: Shared command body content The body content of commands SHALL be shared across all tools. #### Scenario: Same instructions across tools - **WHEN** generating the 'explore' command for Claude and Cursor - **THEN** both SHALL use the same `body` content - **AND** only the frontmatter and file path SHALL differ ================================================ FILE: openspec/changes/archive/2026-02-17-multi-provider-skill-generation/tasks.md ================================================ ## 1. Extend AIToolOption Interface - [x] 1.1 Add `skillsDir?: string` field to `AIToolOption` interface in `src/core/config.ts` ## 2. Add skillsDir to AI_TOOLS - [x] 2.1 Add `skillsDir: '.claude'` to Claude Code tool entry - [x] 2.2 Add `skillsDir: '.cursor'` to Cursor tool entry - [x] 2.3 Add `skillsDir: '.windsurf'` to Windsurf tool entry - [x] 2.4 Add skillsDir for other tools with known Agent Skills spec support (codex, opencode, roocode, kilocode, gemini, factory, github-copilot) ## 3. Create Command Generation Types - [x] 3.1 Create `src/core/command-generation/types.ts` with `CommandContent` interface - [x] 3.2 Add `ToolCommandAdapter` interface to types.ts - [x] 3.3 Export types from module index ## 4. Implement Tool Command Adapters - [x] 4.1 Create `src/core/command-generation/adapters/claude.ts` with Claude frontmatter format - [x] 4.2 Create `src/core/command-generation/adapters/cursor.ts` with Cursor frontmatter format - [x] 4.3 Create `src/core/command-generation/adapters/windsurf.ts` with Windsurf frontmatter format - [x] 4.4 Create base adapter or utility for shared YAML formatting logic (if applicable) ## 5. Create Command Adapter Registry - [x] 5.1 Create `src/core/command-generation/registry.ts` with `CommandAdapterRegistry` class - [x] 5.2 Register Claude, Cursor, Windsurf adapters in static initializer - [x] 5.3 Add `get(toolId)` and `getAll()` methods ## 6. Create Command Generator - [x] 6.1 Create `src/core/command-generation/generator.ts` with `generateCommand()` function - [x] 6.2 Add `generateCommands()` function for batch generation - [x] 6.3 Create module index `src/core/command-generation/index.ts` exporting public API ## 7. Update artifact-experimental-setup Command - [x] 7.1 Add `--tool ` option (required) to command in `src/commands/artifact-workflow.ts` - [x] 7.2 Add validation: `--tool` flag is required (error if missing with list of valid tools) - [x] 7.3 Add validation: tool exists in AI_TOOLS - [x] 7.4 Add validation: tool has skillsDir configured - [x] 7.5 Replace hardcoded `.claude` skill paths with `tool.skillsDir` - [x] 7.6 Replace hardcoded command generation with `CommandAdapterRegistry.get()` + `generateCommands()` - [x] 7.7 Handle missing adapter gracefully (skip commands with message) - [x] 7.8 Update output messages to show target tool name and paths ## 8. Testing - [x] 8.1 Add unit tests for `CommandContent` and `ToolCommandAdapter` contracts - [x] 8.2 Add unit tests for Claude adapter (path + frontmatter format) - [x] 8.3 Add unit tests for Cursor adapter (path + frontmatter format) - [x] 8.4 Add unit tests for `CommandAdapterRegistry.get()` and missing adapter case - [x] 8.5 Add integration test for `--tool` flag validation - [x] 8.6 Verify cross-platform path handling uses `path.join()` throughout ================================================ FILE: openspec/changes/archive/2026-02-17-project-config/.openspec.yaml ================================================ schema: spec-driven created: "2025-01-13" ================================================ FILE: openspec/changes/archive/2026-02-17-project-config/design.md ================================================ # Design: Project Config ## Context OpenSpec currently has a fixed schema resolution order: 1. `--schema` CLI flag 2. `.openspec.yaml` in change directory 3. Hardcoded default: `"spec-driven"` This forces users who want project-level customization to fork entire schemas, even for simple additions like injecting tech stack context or adding artifact-specific rules. The proposal introduces `openspec/config.yaml` as a lightweight customization layer that sits between preset schemas and full forking. It allows teams to: - Set a default schema - Inject project context into all artifacts - Add per-artifact rules **Constraints:** - Must not break existing changes that lack config - Must maintain clean separation between "configure" (this) and "fork" (project-local-schemas) - Config is project-level only (no global/user-level config) **Key stakeholders:** - OpenSpec users who need light customization without forking - Teams sharing workflow conventions via committed config ## Goals / Non-Goals **Goals:** - Load and parse `openspec/config.yaml` using Zod schema - Use config's `schema` field as default in schema resolution - Inject `context` into all artifact instructions - Inject `rules` into matching artifact instructions only - Gracefully handle missing or invalid config (fallback to defaults) **Non-Goals:** - Structural changes to schemas (`skip`, `add`, inheritance) - those belong in fork path - File references for context (`context: ./file.md`) - start with strings - Global user-level config (XDG dirs, etc.) - Config management commands (`openspec config init`) - manual creation for now - Migration from old setups (no existing config to migrate from) ## Decisions ### 1. Config File Format: YAML vs JSON **Decision:** Use YAML (`.yaml` extension, support `.yml` alias) **Rationale:** - YAML supports multi-line strings naturally (`context: |`) - More readable for documentation-heavy content - Consistent with `.openspec.yaml` used in changes - Easy to parse with existing `yaml` library **Alternatives considered:** - JSON: More strict, but poor multi-line string UX - TOML: Less familiar to most users ### 2. Config Location: Project Root vs openspec/ Directory **Decision:** `./openspec/config.yaml` (inside openspec directory) **Rationale:** - Co-located with `openspec/schemas/` (project-local-schemas) - Keeps project root clean - Natural namespace for OpenSpec configuration - Mirrors structure used by other tools (e.g., `.github/`) **Alternatives considered:** - `./openspec.config.yaml` in root: Pollutes root, less clear ownership - XDG config directories: Out of scope, no global config yet ### 3. Context Injection: XML Tags vs Markdown Sections **Decision:** Use XML-style tags `` and `` **Rationale:** - Clear delimiters that don't conflict with Markdown - Agents can easily parse structure - Matches existing patterns in the codebase for special sections **Example:** ```xml Tech stack: TypeScript, React - Include rollback plan ``` **Alternatives considered:** - Markdown headers: Conflicts with template content - Comments: Less visible to agents ### 4. Schema Resolution: Insert Position **Decision:** Config's `schema` field goes between change metadata and hardcoded default **New resolution order:** 1. `--schema` CLI flag (explicit override) 2. `.openspec.yaml` in change directory (change-specific binding) 3. **`openspec/config.yaml` schema field** (NEW - project default) 4. `"spec-driven"` (hardcoded fallback) **Rationale:** - Preserves CLI and change-level overrides (most specific wins) - Makes config act as a "project default" - Backwards compatible (no existing configs to conflict with) ### 5. Rules Validation: Strict vs Permissive **Decision:** Warn on unknown artifact IDs, don't error **Rationale:** - Future-proof: If schema adds new artifacts, old configs don't break - Dev experience: Typos show warnings, but don't halt workflow - User can fix incrementally **Example:** ```yaml rules: proposal: [...] testplan: [...] # Schema doesn't have this artifact → WARN, not ERROR ``` ### 6. Error Handling: Config Parse Failures **Decision:** Log warning and fall back to defaults (don't halt commands) **Rationale:** - Syntax errors in config shouldn't break all of OpenSpec - User can fix config incrementally - Commands remain usable during config development **Warning message:** ``` ⚠️ Failed to parse openspec/config.yaml: [error details] Falling back to default schema (spec-driven) ``` ## Implementation Plan ### Phase 1: Core Types and Loading **File: `src/core/project-config.ts` (NEW)** ```typescript import { z } from 'zod'; import { readFileSync, existsSync } from 'fs'; import { parse as parseYaml } from 'yaml'; import { findProjectRoot } from '../utils/path-utils'; /** * Zod schema for project configuration. * * Purpose: * 1. Documentation - clearly defines the config file structure * 2. Type safety - TypeScript infers ProjectConfig type from schema * 3. Runtime validation - uses safeParse() for resilient field-by-field validation * * Why Zod over manual validation: * - Helps understand OpenSpec's data interfaces at a glance * - Single source of truth for type and validation * - Consistent with other OpenSpec schemas */ export const ProjectConfigSchema = z.object({ schema: z.string().min(1).describe('The workflow schema to use (e.g., "spec-driven", "tdd")'), context: z.string().optional().describe('Project context injected into all artifact instructions'), rules: z.record( z.string(), z.array(z.string()) ).optional().describe('Per-artifact rules, keyed by artifact ID'), }); export type ProjectConfig = z.infer; const MAX_CONTEXT_SIZE = 50 * 1024; // 50KB hard limit /** * Read and parse openspec/config.yaml from project root. * Uses resilient parsing - validates each field independently using Zod safeParse. * Returns null if file doesn't exist. * Returns partial config if some fields are invalid (with warnings). */ export function readProjectConfig(): ProjectConfig | null { const projectRoot = findProjectRoot(); // Try both .yaml and .yml, prefer .yaml let configPath = path.join(projectRoot, 'openspec', 'config.yaml'); if (!existsSync(configPath)) { configPath = path.join(projectRoot, 'openspec', 'config.yml'); if (!existsSync(configPath)) { return null; // No config is OK } } try { const content = readFileSync(configPath, 'utf-8'); const raw = parseYaml(content); if (!raw || typeof raw !== 'object') { console.warn(`⚠️ openspec/config.yaml is not a valid YAML object`); return null; } const config: Partial = {}; // Parse schema field using Zod const schemaField = z.string().min(1); const schemaResult = schemaField.safeParse(raw.schema); if (schemaResult.success) { config.schema = schemaResult.data; } else if (raw.schema !== undefined) { console.warn(`⚠️ Invalid 'schema' field in config (must be non-empty string)`); } // Parse context field with size limit if (raw.context !== undefined) { const contextField = z.string(); const contextResult = contextField.safeParse(raw.context); if (contextResult.success) { const contextSize = Buffer.byteLength(contextResult.data, 'utf-8'); if (contextSize > MAX_CONTEXT_SIZE) { console.warn( `⚠️ Context too large (${(contextSize / 1024).toFixed(1)}KB, limit: ${MAX_CONTEXT_SIZE / 1024}KB)` ); console.warn(` Ignoring context field`); } else { config.context = contextResult.data; } } else { console.warn(`⚠️ Invalid 'context' field in config (must be string)`); } } // Parse rules field using Zod if (raw.rules !== undefined) { const rulesField = z.record(z.string(), z.array(z.string())); // First check if it's an object structure if (typeof raw.rules === 'object' && !Array.isArray(raw.rules)) { const parsedRules: Record = {}; let hasValidRules = false; for (const [artifactId, rules] of Object.entries(raw.rules)) { const rulesArrayResult = z.array(z.string()).safeParse(rules); if (rulesArrayResult.success) { // Filter out empty strings const validRules = rulesArrayResult.data.filter(r => r.length > 0); if (validRules.length > 0) { parsedRules[artifactId] = validRules; hasValidRules = true; } if (validRules.length < rulesArrayResult.data.length) { console.warn( `⚠️ Some rules for '${artifactId}' are empty strings, ignoring them` ); } } else { console.warn( `⚠️ Rules for '${artifactId}' must be an array of strings, ignoring this artifact's rules` ); } } if (hasValidRules) { config.rules = parsedRules; } } else { console.warn(`⚠️ Invalid 'rules' field in config (must be object)`); } } // Return partial config even if some fields failed return Object.keys(config).length > 0 ? (config as ProjectConfig) : null; } catch (error) { console.warn(`⚠️ Failed to parse openspec/config.yaml:`, error); return null; } } /** * Validate artifact IDs in rules against a schema's artifacts. * Called during instruction loading (when schema is known). * Returns warnings for unknown artifact IDs. */ export function validateConfigRules( rules: Record, validArtifactIds: Set, schemaName: string ): string[] { const warnings: string[] = []; for (const artifactId of Object.keys(rules)) { if (!validArtifactIds.has(artifactId)) { const validIds = Array.from(validArtifactIds).sort().join(', '); warnings.push( `Unknown artifact ID in rules: "${artifactId}". ` + `Valid IDs for schema "${schemaName}": ${validIds}` ); } } return warnings; } /** * Suggest valid schema names when user provides invalid schema. * Uses fuzzy matching to find similar names. */ export function suggestSchemas( invalidSchemaName: string, availableSchemas: { name: string; isBuiltIn: boolean }[] ): string { // Simple fuzzy match: Levenshtein distance function levenshtein(a: string, b: string): number { const matrix: number[][] = []; for (let i = 0; i <= b.length; i++) { matrix[i] = [i]; } for (let j = 0; j <= a.length; j++) { matrix[0][j] = j; } for (let i = 1; i <= b.length; i++) { for (let j = 1; j <= a.length; j++) { if (b.charAt(i - 1) === a.charAt(j - 1)) { matrix[i][j] = matrix[i - 1][j - 1]; } else { matrix[i][j] = Math.min( matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1 ); } } } return matrix[b.length][a.length]; } // Find closest matches (distance <= 3) const suggestions = availableSchemas .map(s => ({ ...s, distance: levenshtein(invalidSchemaName, s.name) })) .filter(s => s.distance <= 3) .sort((a, b) => a.distance - b.distance) .slice(0, 3); const builtIn = availableSchemas.filter(s => s.isBuiltIn).map(s => s.name); const projectLocal = availableSchemas.filter(s => !s.isBuiltIn).map(s => s.name); let message = `❌ Schema '${invalidSchemaName}' not found in openspec/config.yaml\n\n`; if (suggestions.length > 0) { message += `Did you mean one of these?\n`; suggestions.forEach(s => { const type = s.isBuiltIn ? 'built-in' : 'project-local'; message += ` - ${s.name} (${type})\n`; }); message += '\n'; } message += `Available schemas:\n`; if (builtIn.length > 0) { message += ` Built-in: ${builtIn.join(', ')}\n`; } if (projectLocal.length > 0) { message += ` Project-local: ${projectLocal.join(', ')}\n`; } else { message += ` Project-local: (none found)\n`; } message += `\nFix: Edit openspec/config.yaml and change 'schema: ${invalidSchemaName}' to a valid schema name`; return message; } ``` ### Phase 2: Schema Resolution **File: `src/utils/change-metadata.ts`** Update `resolveSchemaForChange()` to check config: ```typescript export function resolveSchemaForChange( changeName: string, cliSchema?: string ): string { // 1. CLI flag wins if (cliSchema) { return cliSchema; } // 2. Change metadata (.openspec.yaml) const metadata = readChangeMetadata(changeName); if (metadata?.schema) { return metadata.schema; } // 3. Project config (NEW) const projectConfig = readProjectConfig(); if (projectConfig?.schema) { return projectConfig.schema; } // 4. Hardcoded default return 'spec-driven'; } ``` **File: `src/utils/change-utils.ts`** Update `createNewChange()` to use config schema: ```typescript export function createNewChange( changeName: string, schema?: string ): void { // Use schema from config if not specified const resolvedSchema = schema ?? readProjectConfig()?.schema ?? 'spec-driven'; // ... rest of change creation logic } ``` ### Phase 3: Instruction Injection and Validation **File: `src/core/artifact-graph/instruction-loader.ts`** Update `loadInstructions()` to inject context, rules, and validate artifact IDs: ```typescript // Session-level cache for validation warnings (avoid repeating same warnings) const shownWarnings = new Set(); export function loadInstructions( changeName: string, artifactId: string ): InstructionOutput { const projectConfig = readProjectConfig(); // Load base instructions from schema const baseInstructions = loadSchemaInstructions(changeName, artifactId); const schema = getSchemaForChange(changeName); // Assumes we have schema loaded // Validate rules artifact IDs (only once per session) if (projectConfig?.rules) { const validArtifactIds = new Set(schema.artifacts.map(a => a.id)); const warnings = validateConfigRules( projectConfig.rules, validArtifactIds, schema.name ); // Show each unique warning only once per session for (const warning of warnings) { if (!shownWarnings.has(warning)) { console.warn(`⚠️ ${warning}`); shownWarnings.add(warning); } } } // Build enriched instruction with XML sections let enrichedInstruction = ''; // Add context (all artifacts) if (projectConfig?.context) { enrichedInstruction += `\n${projectConfig.context}\n\n\n`; } // Add rules (only for matching artifact) const rulesForArtifact = projectConfig?.rules?.[artifactId]; if (rulesForArtifact && rulesForArtifact.length > 0) { enrichedInstruction += `\n`; for (const rule of rulesForArtifact) { enrichedInstruction += `- ${rule}\n`; } enrichedInstruction += `\n\n`; } // Add original template enrichedInstruction += ``; return { ...baseInstructions, instruction: enrichedInstruction, }; } ``` **Note on validation timing:** Rules are validated lazily during instruction loading (not at config load time) because: 1. Schema isn't known at config load time (circular dependency) 2. Warnings shown when user actually uses the feature (better UX) 3. Validation warnings cached per session to avoid spam ### Phase 4: Performance and Caching **Why config is read multiple times:** ```typescript // Example: "openspec instructions proposal --change my-feature" // 1. Schema resolution (to know which schema to use) resolveSchemaForChange('my-feature') → readProjectConfig() // Read #1 // 2. Instruction loading (to inject context and rules) loadInstructions('my-feature', 'proposal') → readProjectConfig() // Read #2 // Result: Config read twice per command // More complex commands may read 3-5 times ``` **Performance Strategy:** V1 approach: No caching, read config fresh each time - Simpler implementation - No cache invalidation complexity - Acceptable if config reads are fast enough **Benchmark targets:** - Typical config (1KB context, 5 artifact rules): **< 10ms** per read (imperceptible even 5x) - Large config (50KB context limit): **< 50ms** per read (acceptable for rare case) **If benchmarks fail:** Add simple caching: ```typescript // Simple in-memory cache with no invalidation let cachedConfig: { mtime: number; config: ProjectConfig | null } | null = null; export function readProjectConfig(): ProjectConfig | null { const projectRoot = findProjectRoot(); const configPath = path.join(projectRoot, 'openspec', 'config.yaml'); if (!existsSync(configPath)) { return null; } const stats = statSync(configPath); const mtime = stats.mtimeMs; // Return cached config if file hasn't changed if (cachedConfig && cachedConfig.mtime === mtime) { return cachedConfig.config; } // Read and parse config const config = parseConfigFile(configPath); // Extracted logic // Cache result cachedConfig = { mtime, config }; return config; } ``` **Performance testing task:** Add to Phase 6 (Testing) - Measure typical config read time (1KB context) - Measure large config read time (50KB context limit) - Measure repeated reads within single command - Document results, add caching only if needed ## Data Flow ``` ┌──────────────────────────────────────────────────────────────┐ │ │ │ User runs: openspec instructions proposal --change foo │ │ │ └────────────────────────────┬─────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────┐ │ resolveSchemaForChange("foo") │ │ │ │ 1. Check CLI flag ✗ │ │ 2. Check .openspec.yaml ✗ │ │ 3. Check openspec/config.yaml ✓ → "spec-driven" │ │ │ └────────────────────────────┬─────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────┐ │ loadInstructions("foo", "proposal") │ │ │ │ 1. Load spec-driven/artifacts/proposal.yaml │ │ 2. Read openspec/config.yaml │ │ 3. Build enriched instruction: │ │ - ... │ │ - ... (if rules.proposal exists) │ │ - │ │ │ └────────────────────────────┬─────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────┐ │ Return InstructionOutput with enriched content │ │ │ │ Agent sees project context + rules + schema template │ │ │ └──────────────────────────────────────────────────────────────┘ ``` ## Risks / Trade-offs **[Risk]** Config typos silently ignored (e.g., wrong artifact ID in rules) → **Mitigation:** Validate and warn on unknown artifact IDs during config load. Don't error to allow forward compatibility. **[Risk]** Context grows too large, pollutes all artifact instructions → **Mitigation:** Document recommended size (< 500 chars). If this becomes an issue, add per-artifact context override later. **[Risk]** YAML parsing errors break OpenSpec commands → **Mitigation:** Catch parse errors, log warning, fall back to defaults. Commands remain functional. **[Risk]** Config cached incorrectly across commands → **Mitigation:** Read config fresh on each `readProjectConfig()` call. No caching layer for v1 (simplicity over perf). **[Trade-off]** Context is injected into ALL artifacts → **Benefit:** Consistent project knowledge across workflow → **Cost:** Can't scope context to specific artifacts (yet) → **Future:** Add `context: { global: "...", proposal: "..." }` if needed **[Trade-off]** Rules use artifact IDs, not human names → **Benefit:** Stable identifiers (IDs don't change) → **Cost:** User needs to know artifact IDs from schema → **Mitigation:** Document common artifact IDs, show in `openspec status` output ## Migration Plan **No migration needed** - this is a new feature with no existing state. **Rollout steps:** 1. Deploy with config loading behind feature flag (optional, for safety) 2. Test with internal project (this repo) 3. Document in README with examples 4. Remove feature flag if used **Rollback strategy:** - Config is additive only (doesn't break existing changes) - If bugs found, config parsing can be disabled with env var - Users can delete config file to restore old behavior ## Open Questions **Q: Should context support file references (`context: ./CONTEXT.md`)?** **A (deferred):** Start with string-only. Add file reference later if users request it. Keeps v1 simple. **Q: Should we support `.yml` alias in addition to `.yaml`?** **A:** Yes, check both extensions. Prefer `.yaml` in docs, but accept `.yml` for users who prefer it. **Q: What if config's schema field references a non-existent schema?** **A:** Schema resolution will fail downstream. Show error when trying to load schema, suggest valid schema names. **Q: Should rules be validated against the resolved schema's artifact IDs?** **A:** Yes, validate and warn, but don't halt. This allows forward compatibility if schema evolves. ================================================ FILE: openspec/changes/archive/2026-02-17-project-config/proposal.md ================================================ # Project Config ## Summary Add `openspec/config.yaml` support for project-level configuration. This enables teams to customize OpenSpec behavior without forking schemas, by providing context and rules that are injected into artifact generation. ## Motivation Currently, customizing OpenSpec requires forking entire schemas: - Must copy all files even to add one rule - Lose updates when openspec upgrades - High friction for simple customizations Most users don't need different workflow structure. They need to: - Provide project context (tech stack, conventions, constraints) - Add rules for specific artifacts (requirements, formatting preferences) ## Design Decisions ### Two-Path Model OpenSpec customization follows two distinct paths: ``` ┌─────────────────────────────────────────────────────────────────┐ │ │ │ CONFIGURE (this change) FORK (project-local-schemas) │ │ ───────────────────── ──────────────────────────── │ │ │ │ Use a preset schema Define your own schema │ │ + add context from scratch │ │ + add rules │ │ │ │ openspec/config.yaml openspec/schemas/my-flow/ │ │ │ │ ✓ Simple ✓ Full control │ │ ✓ Get updates ✗ You maintain everything │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### Config Schema ```yaml # openspec/config.yaml # Required: which workflow schema to use schema: spec-driven # Optional: project context injected into all artifact prompts context: | Tech stack: TypeScript, React, Node.js, PostgreSQL API style: RESTful, documented in docs/api-conventions.md Testing: Jest + React Testing Library We value backwards compatibility for all public APIs # Optional: per-artifact rules (additive) rules: proposal: - Include rollback plan - Identify affected teams and notify in #platform-changes specs: - Use Given/When/Then format - Reference existing patterns before inventing new ones tasks: - Each task should be completable in < 2 hours - Include acceptance criteria ``` ### What's NOT in Config The following were explicitly excluded to keep the model simple: | Feature | Decision | Rationale | |---------|----------|-----------| | `skip: [artifact]` | Not supported | Structural changes belong in fork path | | `add: [{...}]` | Not supported | Structural changes belong in fork path | | `extends: base` | Not supported | No inheritance, fork is full copy | | `context: ./file.md` | Not supported (yet) | Start with string, add file reference later if needed | ### Field Definitions #### `schema` (required) Which workflow schema to use. Can be: - Built-in name: `spec-driven`, `tdd` - Project-local schema name: `my-workflow` (requires project-local-schemas change) This becomes the default schema for: - New changes created without `--schema` flag - Commands run on changes without `.openspec.yaml` metadata #### `context` (optional) A string containing project context. Injected into ALL artifact prompts. Use cases: - Tech stack description - Link to conventions/style guides - Team constraints or preferences - Domain-specific context #### `rules` (optional) Per-artifact rules, keyed by artifact ID. Additive to schema's built-in guidance. ```yaml rules: : - Rule 1 - Rule 2 ``` Rules are injected into the specific artifact's prompt, not all prompts. ### Injection Format When generating instructions for an artifact: ```xml Tech stack: TypeScript, React, Node.js, PostgreSQL API style: RESTful, documented in docs/api-conventions.md ... - Include rollback plan - Identify affected teams and notify in #platform-changes ``` Context appears for all artifacts. Rules only appear for the matching artifact. ### Config Creation Strategy **Why integrate with `artifact-experimental-setup`?** This feature targets **experimental workflow users**. The decision to create config during experimental setup (rather than providing standalone commands) is intentional: **Rationale:** 1. **Single entry point** - Users setting up experimental features are already in "configuration mode" 2. **Contextual timing** - Natural to configure project defaults when setting up workflow 3. **Avoids premature API surface** - No standalone `openspec config init` until feature graduates 4. **Experimental scope** - Keeps config as experimental feature, not stable API 5. **Progressive disclosure** - Users can skip and create manually later if needed **Evolution path:** ``` Today (Experimental): openspec artifact-experimental-setup → prompts for config creation → creates .claude/skills/ → creates openspec/config.yaml Future (When graduating): openspec init → prompts for config creation → creates openspec/ directory → creates openspec/config.yaml + standalone commands: openspec config init openspec config validate openspec config set ``` **Why optional?** Config is **additive**, not required: - OpenSpec works without config (uses defaults) - Users can skip during setup and add manually later - Teams can start simple and add config when they feel friction - No config file in git = no problem, everyone gets defaults **Design principle:** The system never *requires* config, but makes it easy to create when users want customization. ## Scope ### In Scope **Core Config System:** - Define `ProjectConfig` type with Zod schema - Add `readProjectConfig()` function with graceful error handling - Update instruction generation to inject context (all artifacts) - Update instruction generation to inject rules (per-artifact) - Update schema resolution to use config's `schema` field as default - Update `openspec new change` to use config's schema as default **Config Creation (Experimental Setup):** - Extend `artifact-experimental-setup` command to optionally create config - Interactive prompts for schema selection (with description of each schema) - Interactive prompts for project context (optional multi-line input) - Interactive prompts for per-artifact rules (optional) - Validate config immediately after creation - Show clear "skip" option for users who want to create config manually later - Display created config location and usage examples ### Out of Scope - `skip` / `add` for structural changes (use fork path for structural changes) - File reference for context (`context: ./CONTEXT.md`) - start with string, add later if needed - Global user-level config (XDG directories, etc.) - Integration with standard `openspec init` (will add when experimental graduates) - Standalone `openspec config init` command (may add in future change) - `openspec config validate` command (may add in future change) - Config editing/updating commands (users edit YAML directly) ## User Experience ### Setting Up Config (Experimental Workflow) When users set up the experimental workflow, they're prompted to optionally create config: ```bash $ openspec artifact-experimental-setup Setting up experimental artifact workflow... ✓ Created .claude/skills/openspec-explore/SKILL.md ✓ Created .claude/skills/openspec-new-change/SKILL.md ✓ Created .claude/skills/openspec-continue-change/SKILL.md ✓ Created .claude/skills/openspec-apply-change/SKILL.md ✓ Created .claude/skills/openspec-ff-change/SKILL.md ✓ Created .claude/skills/openspec-sync-specs/SKILL.md ✓ Created .claude/skills/openspec-archive-change/SKILL.md ✓ Created .claude/commands/opsx/explore.md ✓ Created .claude/commands/opsx/new.md ✓ Created .claude/commands/opsx/continue.md ✓ Created .claude/commands/opsx/apply.md ✓ Created .claude/commands/opsx/ff.md ✓ Created .claude/commands/opsx/sync.md ✓ Created .claude/commands/opsx/archive.md ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 📋 Project Configuration (Optional) Configure project defaults for OpenSpec workflows. ? Create openspec/config.yaml? (Y/n) Y ? Default schema for new changes? ❯ spec-driven (proposal → specs → design → tasks) tdd (spec → tests → implementation → docs) ? Add project context? (optional) Context is shown to AI when creating artifacts. Examples: tech stack, conventions, style guides, domain knowledge Press Enter to skip, or type/paste context: │ Tech stack: TypeScript, React, Node.js, PostgreSQL │ API style: RESTful, documented in docs/api-conventions.md │ Testing: Jest + React Testing Library │ We value backwards compatibility for all public APIs │ [Press Enter when done] ? Add per-artifact rules? (optional) (Y/n) Y Which artifacts should have custom rules? [Space to select, Enter when done] ◯ proposal ◉ specs ◯ design ◯ tasks ? Rules for specs artifact: Enter rules one per line, press Enter on empty line to finish: │ Use Given/When/Then format for scenarios │ Reference existing patterns before inventing new ones │ [Empty line to finish] ✓ Created openspec/config.yaml ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 🎉 Setup Complete! 📖 Config created at: openspec/config.yaml • Default schema: spec-driven • Project context: Added (4 lines) • Rules: 1 artifact configured Usage: • New changes automatically use 'spec-driven' schema • Context injected into all artifact instructions • Rules applied to matching artifacts To share with team: git add openspec/config.yaml .claude/ git commit -m "Setup OpenSpec experimental workflow with project config" [Rest of experimental setup output...] ``` **Key UX decisions:** 1. **Prompted during setup** - Natural place since users are already configuring experimental features 2. **Optional at every step** - Clear skip options, no forced configuration 3. **Guided prompts** - Schema descriptions, example context, artifact selection 4. **Immediate validation** - Config is validated after creation, errors shown immediately 5. **Clear output** - Shows exactly what was created and how it affects workflow ### Setting Up Config (Manual Creation) Users can also create config manually (or skip during setup and add later): ```bash # Create config file manually cat > openspec/config.yaml << 'EOF' schema: spec-driven context: | Tech stack: TypeScript, React, Node.js We follow REST conventions documented in docs/api.md All changes require backwards compatibility consideration rules: proposal: - Must include rollback plan - Must identify affected teams specs: - Use Given/When/Then format EOF ``` ### Effect on Workflow Once config is created, it affects the experimental workflow in three ways: **1. Default Schema Selection** ```bash # Before config: must specify schema /opsx:new my-feature --schema spec-driven # After config (with schema: spec-driven): schema is automatic /opsx:new my-feature # Automatically uses spec-driven from config # Override still works /opsx:new my-feature --schema tdd # Uses tdd, ignoring config ``` **2. Context Injection (All Artifacts)** ```bash # Get instructions for any artifact openspec instructions proposal --change my-feature # Output now includes project context: Tech stack: TypeScript, React, Node.js, PostgreSQL API style: RESTful, documented in docs/api-conventions.md Testing: Jest + React Testing Library We value backwards compatibility for all public APIs ``` Context appears in instructions for **all artifacts** (proposal, specs, design, tasks). **3. Rules Injection (Per-Artifact)** ```bash # Get instructions for artifact with rules configured openspec instructions specs --change my-feature # Output includes artifact-specific rules: [Project context] - Use Given/When/Then format for scenarios - Reference existing patterns before inventing new ones ``` Rules only appear for the **specific artifact** they're configured for. **Artifacts without rules** (e.g., design, tasks) don't get a `` section: ```bash openspec instructions design --change my-feature # Output: then