├── .github ├── CODEOWNERS └── workflows │ └── release-prepare.yml ├── bin └── openspec.js ├── src ├── utils │ ├── index.ts │ ├── interactive.ts │ ├── match.ts │ └── task-progress.ts ├── index.ts └── core │ ├── templates │ ├── claude-template.ts │ ├── cline-template.ts │ ├── costrict-template.ts │ ├── agents-root-stub.ts │ ├── project-template.ts │ └── index.ts │ ├── configurators │ ├── base.ts │ ├── slash │ │ ├── kilocode.ts │ │ ├── gemini.ts │ │ ├── antigravity.ts │ │ ├── roocode.ts │ │ ├── windsurf.ts │ │ ├── cline.ts │ │ ├── github-copilot.ts │ │ ├── auggie.ts │ │ ├── costrict.ts │ │ ├── iflow.ts │ │ ├── crush.ts │ │ ├── cursor.ts │ │ ├── claude.ts │ │ ├── codebuddy.ts │ │ ├── factory.ts │ │ └── amazon-q.ts │ ├── iflow.ts │ ├── claude.ts │ ├── cline.ts │ ├── costrict.ts │ ├── codebuddy.ts │ ├── agents.ts │ ├── qwen.ts │ ├── registry.ts │ └── qoder.ts │ ├── styles │ └── palette.ts │ ├── index.ts │ ├── schemas │ ├── index.ts │ ├── spec.schema.ts │ ├── base.schema.ts │ └── change.schema.ts │ ├── validation │ └── types.ts │ └── converters │ └── json-converter.ts ├── assets └── openspec_dashboard.png ├── test ├── fixtures │ └── tmp-init │ │ └── openspec │ │ ├── changes │ │ └── c1 │ │ │ ├── proposal.md │ │ │ └── specs │ │ │ └── alpha │ │ │ └── spec.md │ │ └── specs │ │ └── alpha │ │ └── spec.md └── commands │ ├── spec.interactive-show.test.ts │ ├── spec.interactive-validate.test.ts │ ├── change.interactive-show.test.ts │ ├── validate.enriched-output.test.ts │ └── change.interactive-validate.test.ts ├── vitest.setup.ts ├── .changeset ├── README.md └── config.json ├── .coderabbit.yaml ├── openspec ├── changes │ ├── archive │ │ ├── 2025-08-11-add-complexity-guidelines │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-09-29-sort-active-changes-by-progress │ │ │ ├── tasks.md │ │ │ ├── specs │ │ │ │ └── cli-view │ │ │ │ │ └── spec.md │ │ │ └── proposal.md │ │ ├── 2025-08-19-add-change-commands │ │ │ ├── specs │ │ │ │ ├── cli-list │ │ │ │ │ └── spec.md │ │ │ │ └── cli-change │ │ │ │ │ └── spec.md │ │ │ ├── proposal.md │ │ │ ├── tasks.md │ │ │ └── design.md │ │ ├── 2025-08-19-add-zod-validation │ │ │ ├── specs │ │ │ │ ├── cli-diff │ │ │ │ │ └── spec.md │ │ │ │ └── cli-archive │ │ │ │ │ └── spec.md │ │ │ └── proposal.md │ │ ├── 2025-10-14-update-cli-init-enter-selection │ │ │ ├── tasks.md │ │ │ ├── proposal.md │ │ │ └── specs │ │ │ │ └── cli-init │ │ │ │ └── spec.md │ │ ├── 2025-10-22-add-crush-support │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-09-29-update-markdown-parser-crlf │ │ │ ├── specs │ │ │ │ └── cli-validate │ │ │ │ │ └── spec.md │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-10-14-update-cli-init-root-agents │ │ │ ├── specs │ │ │ │ └── cli-update │ │ │ │ │ └── spec.md │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-08-13-add-diff-command │ │ │ ├── proposal.md │ │ │ └── tasks.md │ │ ├── 2025-09-29-improve-init-onboarding │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-10-14-improve-agent-instruction-usability │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-10-22-add-cline-support │ │ │ ├── proposal.md │ │ │ └── tasks.md │ │ ├── 2025-08-19-add-spec-commands │ │ │ ├── proposal.md │ │ │ ├── tasks.md │ │ │ ├── specs │ │ │ │ └── cli-spec │ │ │ │ │ └── spec.md │ │ │ └── design.md │ │ ├── 2025-01-13-add-list-command │ │ │ ├── proposal.md │ │ │ └── tasks.md │ │ ├── 2025-10-14-enhance-validation-error-messages │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-10-14-slim-root-agents-file │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-08-05-initialize-typescript-project │ │ │ ├── proposal.md │ │ │ └── tasks.md │ │ ├── 2025-09-29-update-agent-file-name │ │ │ ├── tasks.md │ │ │ ├── specs │ │ │ │ ├── cli-update │ │ │ │ │ └── spec.md │ │ │ │ ├── openspec-conventions │ │ │ │ │ └── spec.md │ │ │ │ └── cli-init │ │ │ │ │ └── spec.md │ │ │ └── proposal.md │ │ ├── 2025-08-13-add-archive-command │ │ │ ├── proposal.md │ │ │ └── tasks.md │ │ ├── 2025-10-22-add-factory-slash-commands │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-10-22-add-archive-command-arguments │ │ │ ├── tasks.md │ │ │ ├── proposal.md │ │ │ └── specs │ │ │ │ └── cli-update │ │ │ │ └── spec.md │ │ ├── 2025-10-14-add-non-interactive-init-options │ │ │ ├── proposal.md │ │ │ └── tasks.md │ │ ├── 2025-08-19-fix-update-tool-selection │ │ │ ├── tasks.md │ │ │ ├── specs │ │ │ │ └── cli-update │ │ │ │ │ └── spec.md │ │ │ └── proposal.md │ │ ├── 2025-09-29-add-multi-agent-init │ │ │ └── tasks.md │ │ ├── 2025-08-19-structured-spec-format │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-09-29-improve-cli-e2e-plan │ │ │ └── tasks.md │ │ ├── 2025-08-19-adopt-verb-noun-cli-structure │ │ │ ├── design.md │ │ │ ├── specs │ │ │ │ └── openspec-conventions │ │ │ │ │ └── spec.md │ │ │ └── tasks.md │ │ ├── 2025-08-19-bulk-validation-interactive-selection │ │ │ ├── specs │ │ │ │ ├── cli-change │ │ │ │ │ └── spec.md │ │ │ │ └── cli-spec │ │ │ │ │ └── spec.md │ │ │ └── proposal.md │ │ ├── 2025-08-19-improve-validate-error-messages │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-08-19-add-interactive-show-command │ │ │ ├── specs │ │ │ │ ├── cli-spec │ │ │ │ │ └── spec.md │ │ │ │ └── cli-change │ │ │ │ │ └── spec.md │ │ │ └── proposal.md │ │ ├── 2025-08-19-add-skip-specs-archive-option │ │ │ └── proposal.md │ │ ├── 2025-10-14-add-kilocode-workflows │ │ │ ├── tasks.md │ │ │ ├── specs │ │ │ │ └── cli-update │ │ │ │ │ └── spec.md │ │ │ └── proposal.md │ │ ├── 2025-12-20-add-global-config-dir │ │ │ ├── proposal.md │ │ │ └── tasks.md │ │ ├── 2025-09-29-improve-deterministic-tests │ │ │ └── tasks.md │ │ ├── 2025-08-06-adopt-future-state-storage │ │ │ ├── proposal.md │ │ │ └── tasks.md │ │ ├── 2025-09-29-add-agents-md-config │ │ │ └── tasks.md │ │ ├── 2025-09-29-add-slash-command-support │ │ │ ├── tasks.md │ │ │ └── specs │ │ │ │ ├── cli-update │ │ │ │ └── spec.md │ │ │ │ └── cli-init │ │ │ │ └── spec.md │ │ ├── 2025-01-11-add-update-command │ │ │ ├── tasks.md │ │ │ └── proposal.md │ │ ├── 2025-10-14-add-windsurf-workflows │ │ │ ├── tasks.md │ │ │ ├── specs │ │ │ │ └── cli-update │ │ │ │ │ └── spec.md │ │ │ └── proposal.md │ │ ├── 2025-10-14-update-release-automation │ │ │ └── tasks.md │ │ ├── 2025-09-29-remove-diff-command │ │ │ └── tasks.md │ │ ├── 2025-08-06-add-init-command │ │ │ ├── proposal.md │ │ │ └── tasks.md │ │ ├── 2025-09-12-add-view-dashboard-command │ │ │ ├── proposal.md │ │ │ └── tasks.md │ │ ├── 2025-08-19-adopt-delta-based-changes │ │ │ └── specs │ │ │ │ ├── cli-archive │ │ │ │ └── spec.md │ │ │ │ └── cli-diff │ │ │ │ └── spec.md │ │ ├── 2025-10-14-add-codex-slash-command-support │ │ │ └── tasks.md │ │ └── 2025-10-14-add-github-copilot-prompts │ │ │ └── tasks.md │ ├── make-validation-scope-aware │ │ ├── proposal.md │ │ ├── tasks.md │ │ └── specs │ │ │ └── cli-validate │ │ │ └── spec.md │ ├── fix-cline-workflows-implementation │ │ ├── specs │ │ │ └── cli-init │ │ │ │ └── spec.md │ │ ├── tasks.md │ │ └── proposal.md │ ├── add-antigravity-support │ │ ├── specs │ │ │ ├── cli-update │ │ │ │ └── spec.md │ │ │ └── cli-init │ │ │ │ └── spec.md │ │ ├── proposal.md │ │ └── tasks.md │ ├── add-scaffold-command │ │ ├── proposal.md │ │ └── tasks.md │ └── add-config-command │ │ └── proposal.md └── project.md ├── tsconfig.json ├── vitest.config.ts ├── AGENTS.md ├── LICENSE └── scripts └── test-postinstall.sh /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Default code ownership 2 | * @TabishB 3 | -------------------------------------------------------------------------------- /bin/openspec.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import '../dist/cli/index.js'; -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | // Shared utilities will be implemented here 2 | export {}; -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './cli/index.js'; 2 | export * from './core/index.js'; -------------------------------------------------------------------------------- /assets/openspec_dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyBoyM/OpenSpec/main/assets/openspec_dashboard.png -------------------------------------------------------------------------------- /src/core/templates/claude-template.ts: -------------------------------------------------------------------------------- 1 | export { agentsRootStubTemplate as claudeTemplate } from './agents-root-stub.js'; 2 | -------------------------------------------------------------------------------- /src/core/templates/cline-template.ts: -------------------------------------------------------------------------------- 1 | export { agentsRootStubTemplate as clineTemplate } from './agents-root-stub.js'; 2 | -------------------------------------------------------------------------------- /src/core/templates/costrict-template.ts: -------------------------------------------------------------------------------- 1 | export { agentsRootStubTemplate as costrictTemplate } from './agents-root-stub.js'; 2 | -------------------------------------------------------------------------------- /test/fixtures/tmp-init/openspec/changes/c1/proposal.md: -------------------------------------------------------------------------------- 1 | # Test Change 2 | 3 | ## Why 4 | Because reasons that are sufficiently long for validation. 5 | 6 | ## What Changes 7 | - **alpha:** Add something 8 | -------------------------------------------------------------------------------- /vitest.setup.ts: -------------------------------------------------------------------------------- 1 | import { ensureCliBuilt } from './test/helpers/run-cli.js'; 2 | 3 | // Ensure the CLI bundle exists before tests execute 4 | export async function setup() { 5 | await ensureCliBuilt(); 6 | } 7 | -------------------------------------------------------------------------------- /src/core/configurators/base.ts: -------------------------------------------------------------------------------- 1 | export interface ToolConfigurator { 2 | name: string; 3 | configFileName: string; 4 | isAvailable: boolean; 5 | configure(projectPath: string, openspecDir: string): Promise; 6 | } -------------------------------------------------------------------------------- /src/core/styles/palette.ts: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | 3 | export const PALETTE = { 4 | white: chalk.hex('#f4f4f4'), 5 | lightGray: chalk.hex('#c8c8c8'), 6 | midGray: chalk.hex('#8a8a8a'), 7 | darkGray: chalk.hex('#4a4a4a') 8 | }; 9 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | This directory is managed by Changesets. 2 | 3 | - Add a changeset locally with `pnpm changeset`. 4 | - The CI "Release (prepare)" workflow opens/updates a Version Packages PR. 5 | - Publishing happens from a GitHub Release via the "Publish to npm" workflow. 6 | 7 | -------------------------------------------------------------------------------- /src/core/index.ts: -------------------------------------------------------------------------------- 1 | // Core OpenSpec logic will be implemented here 2 | export { 3 | GLOBAL_CONFIG_DIR_NAME, 4 | GLOBAL_CONFIG_FILE_NAME, 5 | type GlobalConfig, 6 | getGlobalConfigDir, 7 | getGlobalConfigPath, 8 | getGlobalConfig, 9 | saveGlobalConfig 10 | } from './global-config.js'; -------------------------------------------------------------------------------- /.coderabbit.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json 2 | # Minimal configuration for getting started 3 | language: "en-US" 4 | reviews: 5 | profile: "chill" 6 | high_level_summary: true 7 | auto_review: 8 | enabled: true 9 | drafts: false 10 | base_branches: 11 | - ".*" -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/core/schemas/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ScenarioSchema, 3 | RequirementSchema, 4 | type Scenario, 5 | type Requirement, 6 | } from './base.schema.js'; 7 | 8 | export { 9 | SpecSchema, 10 | type Spec, 11 | } from './spec.schema.js'; 12 | 13 | export { 14 | DeltaOperationType, 15 | DeltaSchema, 16 | ChangeSchema, 17 | type DeltaOperation, 18 | type Delta, 19 | type Change, 20 | } from './change.schema.js'; -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-11-add-complexity-guidelines/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Update OpenSpec README 4 | - [x] 1.1 Add "Start Simple" section after Core Principle 5 | - [x] 1.2 Add complexity triggers to "When to Create Change Proposals" section 6 | - [x] 1.3 Update AI workflow guidance to emphasize minimal implementations 7 | 8 | ## 2. Update CLAUDE.md 9 | - [x] 2.1 Add complexity management rules to project instructions -------------------------------------------------------------------------------- /test/fixtures/tmp-init/openspec/changes/c1/specs/alpha/spec.md: -------------------------------------------------------------------------------- 1 | ## ADDED Requirements 2 | ### Requirement: Parser SHALL accept CRLF change proposals 3 | The parser SHALL accept CRLF change proposals without manual edits. 4 | 5 | #### Scenario: Validate CRLF change 6 | - **GIVEN** a change proposal saved with CRLF line endings 7 | - **WHEN** a developer runs openspec validate on the proposal 8 | - **THEN** validation succeeds without section errors 9 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-sort-active-changes-by-progress/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Dashboard Sorting Logic 4 | - [x] 1.1 Update the Active Changes rendering to sort by completion percentage ascending. 5 | - [x] 1.2 Treat missing progress as 0% and break ties alphabetically by change identifier. 6 | 7 | ## 2. Verification 8 | - [x] 2.1 Add tests that cover different completion percentages and tie cases to confirm deterministic ordering. 9 | -------------------------------------------------------------------------------- /src/core/validation/types.ts: -------------------------------------------------------------------------------- 1 | export type ValidationLevel = 'ERROR' | 'WARNING' | 'INFO'; 2 | 3 | export interface ValidationIssue { 4 | level: ValidationLevel; 5 | path: string; 6 | message: string; 7 | line?: number; 8 | column?: number; 9 | } 10 | 11 | export interface ValidationReport { 12 | valid: boolean; 13 | issues: ValidationIssue[]; 14 | summary: { 15 | errors: number; 16 | warnings: number; 17 | info: number; 18 | }; 19 | } -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-change-commands/specs/cli-list/spec.md: -------------------------------------------------------------------------------- 1 | ## MODIFIED Requirements 2 | 3 | ### Requirement: Command Execution 4 | 5 | The current `list` command behavior SHALL be preserved but marked as deprecated. 6 | 7 | #### Scenario: Deprecation notice 8 | 9 | - **WHEN** using the legacy `list` command 10 | - **THEN** continue to work as before 11 | - **AND** display deprecation notice 12 | - **AND** suggest using `openspec change list` instead -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-zod-validation/specs/cli-diff/spec.md: -------------------------------------------------------------------------------- 1 | ## ADDED Requirements 2 | 3 | ### Requirement: Diff Command Enhancement 4 | 5 | The diff command SHALL validate change structure before displaying differences. 6 | 7 | #### Scenario: Validate before diff 8 | 9 | - **WHEN** executing `openspec diff change-name` 10 | - **THEN** validate change structure 11 | - **AND** show validation warnings if present 12 | - **AND** continue with diff display -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-update-cli-init-enter-selection/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Implementation 2 | - [x] Update the tool selection wizard to auto-select the highlighted tool when Enter is pressed without prior toggles. 3 | - [x] Refresh inline instructions copy so Enter behavior is clear. 4 | - [x] Adjust or add tests if needed to cover the new selection flow. 5 | 6 | ## 2. Validation 7 | - [x] Run `pnpm run build`. 8 | - [x] Run `pnpm test` (or targeted suite) if applicable. 9 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-22-add-crush-support/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Implementation 2 | - [x] 1.1 Create CrushSlashCommandConfigurator class in src/core/configurators/slash/crush.ts 3 | - [x] 1.2 Define file paths for Crush commands (.crush/commands/openspec/) 4 | - [x] 1.3 Create Crush-specific frontmatter for proposal, apply, archive commands 5 | - [x] 1.4 Register Crush configurator in slash/registry.ts 6 | - [x] 1.5 Add Crush to available tools in cli-init command 7 | - [x] 1.6 Test integration with openspec init --tool crush -------------------------------------------------------------------------------- /test/fixtures/tmp-init/openspec/specs/alpha/spec.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | This spec ensures the validation harness exercises a deterministic alpha module for automated tests. 3 | 4 | ## Requirements 5 | 6 | ### Requirement: Alpha module SHALL produce deterministic output 7 | The alpha module SHALL produce a deterministic response for validation. 8 | 9 | #### Scenario: Deterministic alpha run 10 | - **GIVEN** a configured alpha module 11 | - **WHEN** the module runs the default flow 12 | - **THEN** the output matches the expected fixture result 13 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-11-add-complexity-guidelines/proposal.md: -------------------------------------------------------------------------------- 1 | # Add Complexity Management Guidelines 2 | 3 | ## Why 4 | OpenSpec currently lacks guidance on managing complexity, leading to over-engineered solutions when simple ones suffice. 5 | 6 | ## What Changes 7 | - Add "Start Simple" section to openspec/README.md with default minimalism rules 8 | - Add complexity triggers to help identify when complexity is justified 9 | - Enhance AI assistant instructions in CLAUDE.md to bias toward simplicity 10 | 11 | ## Impact 12 | - Affected specs: None (documentation only) 13 | - Affected code: openspec/README.md, CLAUDE.md -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "NodeNext", 5 | "lib": ["ES2022"], 6 | "moduleResolution": "NodeNext", 7 | "rootDir": "./src", 8 | "outDir": "./dist", 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "strict": true, 12 | "skipLibCheck": true, 13 | "declaration": true, 14 | "declarationMap": true, 15 | "sourceMap": true, 16 | "resolveJsonModule": true, 17 | "allowSyntheticDefaultImports": true 18 | }, 19 | "include": ["src/**/*"], 20 | "exclude": ["node_modules", "dist", "test"] 21 | } -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-update-markdown-parser-crlf/specs/cli-validate/spec.md: -------------------------------------------------------------------------------- 1 | ## ADDED Requirements 2 | ### Requirement: Parser SHALL handle cross-platform line endings 3 | The markdown parser SHALL correctly identify sections regardless of line ending format (LF, CRLF, CR). 4 | 5 | #### Scenario: Required sections parsed with CRLF line endings 6 | - **GIVEN** a change proposal markdown saved with CRLF line endings 7 | - **AND** the document contains `## Why` and `## What Changes` 8 | - **WHEN** running `openspec validate ` 9 | - **THEN** validation SHALL recognize the sections and NOT raise parsing errors 10 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-sort-active-changes-by-progress/specs/cli-view/spec.md: -------------------------------------------------------------------------------- 1 | ## MODIFIED Requirements 2 | ### Requirement: Active Changes Display 3 | The dashboard SHALL show active changes with visual progress indicators. 4 | 5 | #### Scenario: Active changes ordered by completion percentage 6 | - **WHEN** multiple active changes are displayed with progress information 7 | - **THEN** list them sorted by completion percentage ascending so 0% items appear first 8 | - **AND** treat missing progress values as 0% for ordering 9 | - **AND** break ties by change identifier in ascending alphabetical order to keep output deterministic 10 | -------------------------------------------------------------------------------- /openspec/changes/make-validation-scope-aware/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | Validation currently errors on changes without spec deltas, even when the change is intentionally proposal-only or tooling-only. This creates false negatives and noisy CI. 3 | 4 | ## What Changes 5 | - Make change validation scope-aware: validate only artifacts that exist. 6 | - Only error on "No deltas found" if spec delta files exist but parse to zero deltas. 7 | - Keep archive stricter: if specs exist but parse to zero deltas, fail; allow `--skip-specs` for tooling-only changes. 8 | 9 | ## Impact 10 | - Affected specs: cli-validate 11 | - Affected code: `src/commands/validate.ts`, `src/core/validation/validator.ts` 12 | 13 | -------------------------------------------------------------------------------- /openspec/changes/fix-cline-workflows-implementation/specs/cli-init/spec.md: -------------------------------------------------------------------------------- 1 | # Delta for CLI Init 2 | 3 | ## MODIFIED Requirements 4 | ### Requirement: Slash Command Configuration 5 | 6 | #### Scenario: Generating slash commands for Cline 7 | - **WHEN** the user selects Cline during initialization 8 | - **THEN** create `.clinerules/workflows/openspec-proposal.md`, `.clinerules/workflows/openspec-apply.md`, and `.clinerules/workflows/openspec-archive.md` 9 | - **AND** populate each file from shared templates so command text matches other tools 10 | - **AND** include Cline-specific Markdown heading frontmatter 11 | - **AND** each template includes instructions for the relevant OpenSpec workflow stage 12 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | test: { 5 | globals: true, 6 | environment: 'node', 7 | globalSetup: './vitest.setup.ts', 8 | // Keep default pool settings; some tests rely on process.chdir, 9 | // which is not supported in worker threads 10 | include: ['test/**/*.test.ts'], 11 | coverage: { 12 | reporter: ['text', 'json', 'html'], 13 | exclude: [ 14 | 'node_modules/', 15 | 'dist/', 16 | 'bin/', 17 | '*.config.ts', 18 | 'build.js', 19 | 'test/**' 20 | ] 21 | }, 22 | testTimeout: 10000, 23 | hookTimeout: 10000 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-22-add-crush-support/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | Add support for Crush AI assistant in OpenSpec to enable developers to use Crush's enhanced capabilities for spec-driven development workflows. 3 | 4 | ## What Changes 5 | - Add Crush slash command configurator for proposal, apply, and archive operations 6 | - Add Crush-specific AGENTS.md configuration template 7 | - Update tool registry to include Crush configurator 8 | - **BREAKING**: None - this is additive functionality 9 | 10 | ## Impact 11 | - Affected specs: cli-init (new tool option) 12 | - Affected code: src/core/configurators/slash/crush.ts, registry.ts 13 | - New files: .crush/commands/openspec/ (proposal.md, apply.md, archive.md) -------------------------------------------------------------------------------- /src/core/schemas/spec.schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | import { RequirementSchema } from './base.schema.js'; 3 | import { VALIDATION_MESSAGES } from '../validation/constants.js'; 4 | 5 | export const SpecSchema = z.object({ 6 | name: z.string().min(1, VALIDATION_MESSAGES.SPEC_NAME_EMPTY), 7 | overview: z.string().min(1, VALIDATION_MESSAGES.SPEC_PURPOSE_EMPTY), 8 | requirements: z.array(RequirementSchema) 9 | .min(1, VALIDATION_MESSAGES.SPEC_NO_REQUIREMENTS), 10 | metadata: z.object({ 11 | version: z.string().default('1.0.0'), 12 | format: z.literal('openspec'), 13 | sourcePath: z.string().optional(), 14 | }).optional(), 15 | }); 16 | 17 | export type Spec = z.infer; -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-zod-validation/specs/cli-archive/spec.md: -------------------------------------------------------------------------------- 1 | ## ADDED Requirements 2 | 3 | ### Requirement: Archive Validation 4 | 5 | The archive command SHALL validate changes before applying them to ensure data integrity. 6 | 7 | #### Scenario: Pre-archive validation 8 | 9 | - **WHEN** executing `openspec archive change-name` 10 | - **THEN** validate the change structure first 11 | - **AND** only proceed if validation passes 12 | - **AND** show validation errors if it fails 13 | 14 | #### Scenario: Force archive without validation 15 | 16 | - **WHEN** executing `openspec archive change-name --no-validate` 17 | - **THEN** skip validation (unsafe mode) 18 | - **AND** show warning about skipping validation -------------------------------------------------------------------------------- /AGENTS.md: -------------------------------------------------------------------------------- 1 | 2 | # OpenSpec Instructions 3 | 4 | These instructions are for AI assistants working in this project. 5 | 6 | Always open `@/openspec/AGENTS.md` when the request: 7 | - Mentions planning or proposals (words like proposal, spec, change, plan) 8 | - Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work 9 | - Sounds ambiguous and you need the authoritative spec before coding 10 | 11 | Use `@/openspec/AGENTS.md` to learn: 12 | - How to create and apply change proposals 13 | - Spec format and conventions 14 | - Project structure and guidelines 15 | 16 | Keep this managed block so 'openspec update' can refresh the instructions. 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/core/templates/agents-root-stub.ts: -------------------------------------------------------------------------------- 1 | export const agentsRootStubTemplate = `# OpenSpec Instructions 2 | 3 | These instructions are for AI assistants working in this project. 4 | 5 | Always open \`@/openspec/AGENTS.md\` when the request: 6 | - Mentions planning or proposals (words like proposal, spec, change, plan) 7 | - Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work 8 | - Sounds ambiguous and you need the authoritative spec before coding 9 | 10 | Use \`@/openspec/AGENTS.md\` to learn: 11 | - How to create and apply change proposals 12 | - Spec format and conventions 13 | - Project structure and guidelines 14 | 15 | Keep this managed block so 'openspec update' can refresh the instructions. 16 | `; 17 | -------------------------------------------------------------------------------- /src/core/schemas/base.schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | import { VALIDATION_MESSAGES } from '../validation/constants.js'; 3 | 4 | export const ScenarioSchema = z.object({ 5 | rawText: z.string().min(1, VALIDATION_MESSAGES.SCENARIO_EMPTY), 6 | }); 7 | 8 | export const RequirementSchema = z.object({ 9 | text: z.string() 10 | .min(1, VALIDATION_MESSAGES.REQUIREMENT_EMPTY) 11 | .refine( 12 | (text) => text.includes('SHALL') || text.includes('MUST'), 13 | VALIDATION_MESSAGES.REQUIREMENT_NO_SHALL 14 | ), 15 | scenarios: z.array(ScenarioSchema) 16 | .min(1, VALIDATION_MESSAGES.REQUIREMENT_NO_SCENARIOS), 17 | }); 18 | 19 | export type Scenario = z.infer; 20 | export type Requirement = z.infer; -------------------------------------------------------------------------------- /openspec/changes/add-antigravity-support/specs/cli-update/spec.md: -------------------------------------------------------------------------------- 1 | ## MODIFIED Requirements 2 | ### Requirement: Slash Command Updates 3 | 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. 4 | 5 | #### Scenario: Updating slash commands for Antigravity 6 | - **WHEN** `.agent/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` 7 | - **THEN** refresh the OpenSpec-managed portion of each file so the workflow copy matches other tools while preserving the existing single-field `description` frontmatter 8 | - **AND** skip creating any missing workflow files during update, mirroring the behavior for Windsurf and other IDEs 9 | -------------------------------------------------------------------------------- /openspec/changes/fix-cline-workflows-implementation/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Update ClineSlashCommandConfigurator 2 | - [x] Change FILE_PATHS in `src/core/configurators/slash/cline.ts` from `.clinerules/openspec-*.md` to `.clinerules/workflows/openspec-*.md` 3 | 4 | ## 2. Update Tests 5 | - [x] Update "should refresh existing Cline rule files" test in `test/core/update.test.ts` to use workflow paths 6 | - [x] Update "should create Cline rule files with templates" test in `test/core/init.test.ts` to use workflow paths 7 | 8 | ## 3. Update Documentation 9 | - [x] Update README.md table to show "Workflows in `.clinerules/workflows/` directory" for Cline 10 | 11 | ## 4. Validate Changes 12 | - [x] Ensure all tests pass with the new paths 13 | - [x] Verify the change follows OpenSpec conventions 14 | -------------------------------------------------------------------------------- /src/core/configurators/slash/kilocode.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from "./base.js"; 2 | import { SlashCommandId } from "../../templates/index.js"; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: ".kilocode/workflows/openspec-proposal.md", 6 | apply: ".kilocode/workflows/openspec-apply.md", 7 | archive: ".kilocode/workflows/openspec-archive.md" 8 | }; 9 | 10 | export class KiloCodeSlashCommandConfigurator extends SlashCommandConfigurator { 11 | readonly toolId = "kilocode"; 12 | readonly isAvailable = true; 13 | 14 | protected getRelativePath(id: SlashCommandId): string { 15 | return FILE_PATHS[id]; 16 | } 17 | 18 | protected getFrontmatter(_id: SlashCommandId): string | undefined { 19 | return undefined; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/utils/interactive.ts: -------------------------------------------------------------------------------- 1 | type InteractiveOptions = { 2 | /** 3 | * Explicit "disable prompts" flag passed by internal callers. 4 | */ 5 | noInteractive?: boolean; 6 | /** 7 | * Commander-style negated option: `--no-interactive` sets this to false. 8 | */ 9 | interactive?: boolean; 10 | }; 11 | 12 | function resolveNoInteractive(value?: boolean | InteractiveOptions): boolean { 13 | if (typeof value === 'boolean') return value; 14 | return value?.noInteractive === true || value?.interactive === false; 15 | } 16 | 17 | export function isInteractive(value?: boolean | InteractiveOptions): boolean { 18 | if (resolveNoInteractive(value)) return false; 19 | if (process.env.OPEN_SPEC_INTERACTIVE === '0') return false; 20 | return !!process.stdin.isTTY; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-update-cli-init-root-agents/specs/cli-update/spec.md: -------------------------------------------------------------------------------- 1 | ## MODIFIED Requirements 2 | ### Requirement: Tool-Agnostic Updates 3 | The update command SHALL refresh OpenSpec-managed files in a predictable manner while respecting each team's chosen tooling. 4 | 5 | #### Scenario: Updating files 6 | - **WHEN** updating files 7 | - **THEN** completely replace `openspec/AGENTS.md` with the latest template 8 | - **AND** create or refresh the root-level `AGENTS.md` stub using the managed marker block, even if the file was previously absent 9 | - **AND** update only the OpenSpec-managed sections inside existing AI tool files, leaving user-authored content untouched 10 | - **AND** avoid creating new native-tool configuration files (slash commands, CLAUDE.md, etc.) unless they already exist 11 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-13-add-diff-command/proposal.md: -------------------------------------------------------------------------------- 1 | # Add Diff Command to OpenSpec CLI 2 | 3 | ## Why 4 | 5 | Developers need to easily view differences between proposed spec changes and current specs without manually comparing files. 6 | 7 | ## What Changes 8 | 9 | - Add `openspec diff [change-name]` command that shows differences between change specs and current specs 10 | - Compare files in `changes/[change-name]/specs/` with corresponding files in `specs/` 11 | - Display unified diff output showing added/removed/modified lines 12 | - Support colored output for better readability 13 | 14 | ## Impact 15 | 16 | - Affected specs: New capability `cli-diff` will be added 17 | - Affected code: 18 | - `src/cli/index.ts` - Add diff command 19 | - `src/core/diff.ts` - New file with diff logic (~80 lines) -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-improve-init-onboarding/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Planning & Spec Updates 2 | - [x] 1.1 Confirm overlap with `add-multi-agent-init` and coordinate extend-mode flow 3 | - [x] 1.2 Update `openspec/specs/cli-init/spec.md` to capture multi-select onboarding requirements 4 | 5 | ## 2. Implementation 6 | - [x] 2.1 Add multi-select support to the `openspec init` prompt, including indicators for existing tool configs 7 | - [x] 2.2 Enhance success messaging to summarize created/refreshed assets per tool 8 | - [x] 2.3 Ensure shared instruction template is applied consistently (CLAUDE.md, AGENTS.md, slash commands) 9 | 10 | ## 3. Quality 11 | - [x] 3.1 Expand unit tests for init/update flows covering multi-select and summaries 12 | - [x] 3.2 Perform `openspec init` smoke test in a temp directory (document output) 13 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-improve-agent-instruction-usability/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Instruction redesign 2 | - [x] 1.1 Draft a quick-reference section that surfaces file templates and formatting rules at the top of `openspec/AGENTS.md`. 3 | - [x] 1.2 Reorganize the workflow narrative with inline examples and progressive disclosure for advanced topics. 4 | 5 | ## 2. Templates and checklists 6 | - [x] 2.1 Add copy/paste templates for proposal, tasks, design, and spec delta files. 7 | - [x] 2.2 Insert a pre-validation checklist capturing common lint failures before running `openspec validate`. 8 | 9 | ## 3. Documentation updates 10 | - [x] 3.1 Update supporting docs or README pointers so contributors find the redesigned instructions. 11 | - [x] 3.2 Confirm examples and references stay in sync with the new scaffold command guidance. 12 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-update-markdown-parser-crlf/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Guard the regression 2 | - [x] 1.1 Add a unit test that feeds a CRLF change document into `MarkdownParser.parseChange` and asserts `Why`/`What Changes` are detected. 3 | - [x] 1.2 Add a CLI spawn/e2e test that writes a CRLF change, runs `openspec validate`, and expects success. 4 | 5 | ## 2. Normalize parsing 6 | - [x] 2.1 Normalize line endings when constructing `MarkdownParser` so headers and content comparisons ignore `\r`. 7 | - [x] 2.2 Ensure all CLI entry points (validate, view, spec conversion) reuse the normalized parser path. 8 | 9 | ## 3. Document and verify 10 | - [x] 3.1 Update the `cli-validate` spec with a scenario covering CRLF line endings. 11 | - [x] 3.2 Run the parser and CLI test suites (`pnpm test`, relevant spawn tests) to confirm the fix. 12 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-22-add-cline-support/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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. 3 | 4 | ## What Changes 5 | - Add Cline slash command configurator for proposal, apply, and archive operations 6 | - Add Cline root CLINE.md configurator for project-level instructions 7 | - Add Cline template exports 8 | - Update tool and slash command registries to include Cline 9 | - Add comprehensive test coverage 10 | - **BREAKING**: None - this is additive functionality 11 | 12 | ## Impact 13 | - Affected specs: cli-init (new tool option) 14 | - Affected code: src/core/configurators/slash/cline.ts, src/core/configurators/cline.ts, registry files 15 | - New files: .clinerules/openspec-*.md, CLINE.md 16 | -------------------------------------------------------------------------------- /src/core/configurators/iflow.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { ToolConfigurator } from "./base.js"; 3 | import { FileSystemUtils } from "../../utils/file-system.js"; 4 | import { TemplateManager } from "../templates/index.js"; 5 | import { OPENSPEC_MARKERS } from "../config.js"; 6 | 7 | export class IflowConfigurator implements ToolConfigurator { 8 | name = "iFlow"; 9 | configFileName = "IFLOW.md"; 10 | isAvailable = true; 11 | 12 | async configure(projectPath: string, openspecDir: string): Promise { 13 | const filePath = path.join(projectPath, this.configFileName); 14 | const content = TemplateManager.getClaudeTemplate(); 15 | 16 | await FileSystemUtils.updateFileWithMarkers( 17 | filePath, 18 | content, 19 | OPENSPEC_MARKERS.start, 20 | OPENSPEC_MARKERS.end 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/core/configurators/claude.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { ToolConfigurator } from './base.js'; 3 | import { FileSystemUtils } from '../../utils/file-system.js'; 4 | import { TemplateManager } from '../templates/index.js'; 5 | import { OPENSPEC_MARKERS } from '../config.js'; 6 | 7 | export class ClaudeConfigurator implements ToolConfigurator { 8 | name = 'Claude Code'; 9 | configFileName = 'CLAUDE.md'; 10 | isAvailable = true; 11 | 12 | async configure(projectPath: string, openspecDir: string): Promise { 13 | const filePath = path.join(projectPath, this.configFileName); 14 | const content = TemplateManager.getClaudeTemplate(); 15 | 16 | await FileSystemUtils.updateFileWithMarkers( 17 | filePath, 18 | content, 19 | OPENSPEC_MARKERS.start, 20 | OPENSPEC_MARKERS.end 21 | ); 22 | } 23 | } -------------------------------------------------------------------------------- /src/core/configurators/cline.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { ToolConfigurator } from './base.js'; 3 | import { FileSystemUtils } from '../../utils/file-system.js'; 4 | import { TemplateManager } from '../templates/index.js'; 5 | import { OPENSPEC_MARKERS } from '../config.js'; 6 | 7 | export class ClineConfigurator implements ToolConfigurator { 8 | name = 'Cline'; 9 | configFileName = 'CLINE.md'; 10 | isAvailable = true; 11 | 12 | async configure(projectPath: string, openspecDir: string): Promise { 13 | const filePath = path.join(projectPath, this.configFileName); 14 | const content = TemplateManager.getClineTemplate(); 15 | 16 | await FileSystemUtils.updateFileWithMarkers( 17 | filePath, 18 | content, 19 | OPENSPEC_MARKERS.start, 20 | OPENSPEC_MARKERS.end 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/core/configurators/costrict.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { ToolConfigurator } from './base.js'; 3 | import { FileSystemUtils } from '../../utils/file-system.js'; 4 | import { TemplateManager } from '../templates/index.js'; 5 | import { OPENSPEC_MARKERS } from '../config.js'; 6 | 7 | export class CostrictConfigurator implements ToolConfigurator { 8 | name = 'CoStrict'; 9 | configFileName = 'COSTRICT.md'; 10 | isAvailable = true; 11 | 12 | async configure(projectPath: string, openspecDir: string): Promise { 13 | const filePath = path.join(projectPath, this.configFileName); 14 | const content = TemplateManager.getCostrictTemplate(); 15 | 16 | await FileSystemUtils.updateFileWithMarkers( 17 | filePath, 18 | content, 19 | OPENSPEC_MARKERS.start, 20 | OPENSPEC_MARKERS.end 21 | ); 22 | } 23 | } -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-spec-commands/proposal.md: -------------------------------------------------------------------------------- 1 | # Change: Add Spec Commands with JSON Output 2 | 3 | ## Why 4 | 5 | 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. 6 | 7 | ## What Changes 8 | 9 | - Add new `openspec spec` command with three subcommands: `show`, `list`, and `validate` 10 | - Implement JSON output capability for specs using heading-based parsing 11 | - Add Zod schemas for spec structure validation 12 | - Enable content filtering options (requirements only, no scenarios, specific requirement) 13 | 14 | ## Impact 15 | 16 | - **Affected specs**: None (new capability) 17 | - **Affected code**: 18 | - src/cli/index.ts (register new command) 19 | - package.json (add zod dependency) 20 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-change-commands/proposal.md: -------------------------------------------------------------------------------- 1 | # Change: Add Change Commands with JSON Output 2 | 3 | ## Why 4 | 5 | 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. 6 | 7 | ## What Changes 8 | 9 | - **cli-change:** Add new command for managing change proposals with show, list, and validate subcommands 10 | - **cli-list:** Add deprecation notice for legacy list command to guide users to the new change list command 11 | 12 | ## Impact 13 | 14 | - **Affected specs**: cli-list (modify to add deprecation notice) 15 | - **Affected code**: 16 | - src/cli/index.ts (register new command) 17 | - src/core/list.ts (add deprecation notice) -------------------------------------------------------------------------------- /src/core/configurators/codebuddy.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { ToolConfigurator } from './base.js'; 3 | import { FileSystemUtils } from '../../utils/file-system.js'; 4 | import { TemplateManager } from '../templates/index.js'; 5 | import { OPENSPEC_MARKERS } from '../config.js'; 6 | 7 | export class CodeBuddyConfigurator implements ToolConfigurator { 8 | name = 'CodeBuddy'; 9 | configFileName = 'CODEBUDDY.md'; 10 | isAvailable = true; 11 | 12 | async configure(projectPath: string, openspecDir: string): Promise { 13 | const filePath = path.join(projectPath, this.configFileName); 14 | const content = TemplateManager.getClaudeTemplate(); 15 | 16 | await FileSystemUtils.updateFileWithMarkers( 17 | filePath, 18 | content, 19 | OPENSPEC_MARKERS.start, 20 | OPENSPEC_MARKERS.end 21 | ); 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-01-13-add-list-command/proposal.md: -------------------------------------------------------------------------------- 1 | # Add List Command to OpenSpec CLI 2 | 3 | ## Why 4 | 5 | Developers need visibility into available changes and their status to understand the project's evolution and pending work. 6 | 7 | ## What Changes 8 | 9 | - Add `openspec list` command that displays all changes in the changes/ directory 10 | - Show each change name with task completion count (e.g., "add-auth: 3/5 tasks") 11 | - Display completion status indicator (✓ for fully complete, progress for partial) 12 | - Skip the archive/ subdirectory to focus on active changes 13 | - Simple table output for easy scanning 14 | 15 | ## Impact 16 | 17 | - Affected specs: New capability `cli-list` will be added 18 | - Affected code: 19 | - `src/cli/index.ts` - Add list command 20 | - `src/core/list.ts` - New file with directory scanning and task parsing (~60 lines) -------------------------------------------------------------------------------- /src/core/configurators/agents.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { ToolConfigurator } from './base.js'; 3 | import { FileSystemUtils } from '../../utils/file-system.js'; 4 | import { TemplateManager } from '../templates/index.js'; 5 | import { OPENSPEC_MARKERS } from '../config.js'; 6 | 7 | export class AgentsStandardConfigurator implements ToolConfigurator { 8 | name = 'AGENTS.md standard'; 9 | configFileName = 'AGENTS.md'; 10 | isAvailable = true; 11 | 12 | async configure(projectPath: string, _openspecDir: string): Promise { 13 | const filePath = path.join(projectPath, this.configFileName); 14 | const content = TemplateManager.getAgentsStandardTemplate(); 15 | 16 | await FileSystemUtils.updateFileWithMarkers( 17 | filePath, 18 | content, 19 | OPENSPEC_MARKERS.start, 20 | OPENSPEC_MARKERS.end 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /openspec/changes/add-antigravity-support/specs/cli-init/spec.md: -------------------------------------------------------------------------------- 1 | ## MODIFIED Requirements 2 | ### Requirement: Slash Command Configuration 3 | The init command SHALL generate slash command files for supported editors using shared templates. 4 | 5 | #### Scenario: Generating slash commands for Antigravity 6 | - **WHEN** the user selects Antigravity during initialization 7 | - **THEN** create `.agent/workflows/openspec-proposal.md`, `.agent/workflows/openspec-apply.md`, and `.agent/workflows/openspec-archive.md` 8 | - **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 9 | - **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 10 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-enhance-validation-error-messages/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Messaging enhancements 2 | - [x] 1.1 Inventory current validation failures and map each to the desired message improvements. 3 | - [x] 1.2 Implement structured error builders that include file paths, normalized header names, and example fixes. 4 | - [x] 1.3 Ensure `openspec validate --help` and troubleshooting docs mention the richer messages and debug tips. 5 | 6 | ## 2. Tests 7 | - [x] 2.1 Add unit tests for representative errors (no deltas, missing requirement body, missing scenarios) asserting the new wording. 8 | - [x] 2.2 Add integration coverage verifying the Next steps footer reflects contextual guidance. 9 | 10 | ## 3. Documentation 11 | - [x] 3.1 Update troubleshooting sections and CLI docs with sample output from the enhanced errors. 12 | - [x] 3.2 Note the change in CHANGELOG or release notes if applicable. 13 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-slim-root-agents-file/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Templates 2 | - [x] 1.1 Add a shared stub template that renders the root agent instructions hand-off message. 3 | - [x] 1.2 Ensure the stub covers both `AGENTS.md` and `CLAUDE.md` variants. 4 | 5 | ## 2. Init Flow 6 | - [x] 2.1 Update `createInitArtifacts` to write the stub to the project root instead of the full instructions. 7 | - [x] 2.2 Preserve the managed block markers so future updates can overwrite the stub safely. 8 | 9 | ## 3. Update Flow 10 | - [x] 3.1 Make the update command refresh the root stub rather than the full instructions. 11 | - [x] 3.2 Confirm the update log output still reflects the files that changed. 12 | 13 | ## 4. Tests & Docs 14 | - [x] 4.1 Adjust CLI/init tests to match the new root content. 15 | - [x] 4.2 Document the stub message in `openspec/specs/cli-init` and `openspec/specs/cli-update` (and any relevant README snippets). 16 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-05-initialize-typescript-project/proposal.md: -------------------------------------------------------------------------------- 1 | # Initialize TypeScript Project 2 | 3 | ## Why 4 | 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. 5 | 6 | ## What Changes 7 | - Create TypeScript project configuration with ESM modules (package.json, tsconfig.json) 8 | - Set up the base directory structure for the CLI implementation 9 | - Configure build scripts and development tooling 10 | - Add essential dependencies for CLI development 11 | - Create .gitignore for Node.js/TypeScript projects 12 | - Set minimum Node.js version to 20.19.0 for native ESM support 13 | 14 | ## Impact 15 | - Affected specs: None (initial project setup) 16 | - Affected code: None (greenfield project) 17 | - New directories: src/, dist/, node_modules/ 18 | - New files: package.json, tsconfig.json, .gitignore, build.js -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-update-agent-file-name/tasks.md: -------------------------------------------------------------------------------- 1 | # Update Agent Instruction File Name - Tasks 2 | 3 | ## 1. Rename Instruction File 4 | - [x] Rename `openspec/README.md` to `openspec/AGENTS.md` 5 | - [x] Update root references to new path 6 | 7 | ## 2. Update Templates 8 | - [x] Rename `src/core/templates/readme-template.ts` to `agents-template.ts` 9 | - [x] Update exported constant from `readmeTemplate` to `agentsTemplate` 10 | 11 | ## 3. Adjust CLI Commands 12 | - [x] Modify `openspec init` to generate `AGENTS.md` 13 | - [x] Update `openspec update` to refresh `AGENTS.md` 14 | - [x] Ensure CLAUDE.md markers link to `@openspec/AGENTS.md` 15 | 16 | ## 4. Update Specifications 17 | - [x] Modify `cli-init` spec to reference `AGENTS.md` 18 | - [x] Modify `cli-update` spec to reference `AGENTS.md` 19 | - [x] Modify `openspec-conventions` spec to include `AGENTS.md` in project structure 20 | 21 | ## 5. Validation 22 | - [x] `pnpm test` 23 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-13-add-archive-command/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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. 3 | 4 | ## What Changes 5 | - Add new `archive` command to CLI that moves changes to `changes/archive/YYYY-MM-DD-[change-name]/` 6 | - Check for incomplete tasks before archiving and warn user 7 | - Allow interactive selection of change to archive 8 | - Prevent archiving if target directory already exists 9 | - Update main specs from the change's future state specs (copy from `changes/[name]/specs/` to `openspec/specs/`) 10 | - Show confirmation prompt before updating specs, displaying which specs will be created/updated 11 | - Support `--yes` flag to skip confirmations for automation 12 | 13 | ## Impact 14 | - Affected specs: cli-archive (new) 15 | - Affected code: src/cli/index.ts, src/core/archive.ts (new) -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-22-add-factory-slash-commands/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Factory tool registration 2 | - [x] 1.1 Add Factory/Droid metadata to the native tool registry used by init/update (ID, display name, command paths, availability flags). 3 | - [x] 1.2 Surface Factory in interactive prompts and non-interactive `--tools` parsing alongside existing slash-command integrations. 4 | 5 | ## 2. Slash command templates 6 | - [x] 2.1 Create shared templates for Factory's `openspec-proposal`, `openspec-apply`, and `openspec-archive` custom commands following Factory's CLI format. 7 | - [x] 2.2 Wire the templates into init/update so generation happens on create and refresh respects OpenSpec markers. 8 | 9 | ## 3. Verification 10 | - [x] 3.1 Update or add automated coverage that ensures Factory command files are scaffolded and refreshed correctly. 11 | - [x] 3.2 Document the new option in any user-facing copy (help text, README snippets) if required by spec. 12 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-13-add-diff-command/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Core Implementation 4 | - [x] 1.1 Create `src/core/diff.ts` with diff logic 5 | - [x] 1.2 Implement change directory scanning 6 | - [x] 1.3 Implement file comparison using unified diff format 7 | - [x] 1.4 Add color support for terminal output 8 | 9 | ## 2. CLI Integration 10 | - [x] 2.1 Add diff command to `src/cli/index.ts` 11 | - [x] 2.2 Implement interactive change selection when no argument provided 12 | - [x] 2.3 Add error handling for missing changes 13 | 14 | ## 3. Enhancements 15 | - [x] 3.1 Replace with jest-diff for professional diff output 16 | - [x] 3.2 Improve file headers with status and statistics 17 | - [x] 3.3 Add summary view with file counts and line changes 18 | 19 | ## 4. Testing 20 | - [ ] 4.1 Test diff generation for modified files 21 | - [ ] 4.2 Test handling of new files 22 | - [ ] 4.3 Test handling of deleted files 23 | - [ ] 4.4 Test interactive mode -------------------------------------------------------------------------------- /src/utils/match.ts: -------------------------------------------------------------------------------- 1 | export function nearestMatches(input: string, candidates: string[], max: number = 5): string[] { 2 | const scored = candidates.map(candidate => ({ candidate, distance: levenshtein(input, candidate) })); 3 | scored.sort((a, b) => a.distance - b.distance); 4 | return scored.slice(0, max).map(s => s.candidate); 5 | } 6 | 7 | export function levenshtein(a: string, b: string): number { 8 | const m = a.length; 9 | const n = b.length; 10 | const dp: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); 11 | for (let i = 0; i <= m; i++) dp[i][0] = i; 12 | for (let j = 0; j <= n; j++) dp[0][j] = j; 13 | for (let i = 1; i <= m; i++) { 14 | for (let j = 1; j <= n; j++) { 15 | const cost = a[i - 1] === b[j - 1] ? 0 : 1; 16 | dp[i][j] = Math.min( 17 | dp[i - 1][j] + 1, 18 | dp[i][j - 1] + 1, 19 | dp[i - 1][j - 1] + cost 20 | ); 21 | } 22 | } 23 | return dp[m][n]; 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-update-cli-init-enter-selection/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | - Users frequently scroll to a tool and press Enter without toggling it, resulting in no configuration changes. 3 | - The current workflow deviates from common CLI expectations where Enter confirms the highlighted item. 4 | - Aligning behavior with user expectations reduces friction during onboarding. 5 | 6 | ## What Changes 7 | - Update the init wizard so pressing Enter on a highlighted tool selects it before moving to the review step. 8 | - Adjust interactive instructions to clarify Enter selects the current tool and Space still toggles selections. 9 | - Refresh specs to capture the clarified behavior for the interactive menu. 10 | 11 | ## Impact 12 | - Users who press Enter without toggling now configure the highlighted tool instead of exiting with no selections. 13 | - Spacebar multi-select support remains unchanged for power users. 14 | - Documentation better reflects how the wizard behaves. 15 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-22-add-archive-command-arguments/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Update OpenCode Configurator 4 | - [x] 1.1 Add `$ARGUMENTS` placeholder to OpenCode archive frontmatter (matching the proposal pattern) 5 | - [x] 1.2 Format it as `\n $ARGUMENTS\n` or similar structure for clarity 6 | - [x] 1.3 Ensure `updateExisting` rewrites the archive frontmatter/body so `$ARGUMENTS` persists after `openspec update` 7 | 8 | ## 2. Update Slash Command Templates 9 | - [x] 2.1 Modify archive steps to validate change ID argument when provided via `$ARGUMENTS` 10 | - [x] 2.2 Keep backward compatibility - allow inferring from context if no argument provided 11 | - [x] 2.3 Add step to validate the change ID exists using `openspec list` before archiving 12 | 13 | ## 3. Update Documentation 14 | - [x] 3.1 Update AGENTS.md archive examples to show argument usage 15 | - [x] 3.2 Document that OpenCode now supports `/openspec:archive ` 16 | -------------------------------------------------------------------------------- /openspec/changes/make-validation-scope-aware/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Validator changes 2 | - [ ] 1.1 Change `validateChangeDeltaSpecs` to only emit "Change must have at least one delta" when `specs/` exists and contains at least one `*/spec.md` but parsed total deltas is 0 3 | - [ ] 1.2 Return valid (no error) when `specs/` directory is missing or has no `spec.md` files 4 | 5 | ## 2. CLI changes 6 | - [ ] 2.1 In bulk validation, keep current behavior (call delta validator). Behavior remains correct after 1.1 7 | - [ ] 2.2 Add a short INFO log in human-readable mode when a change has no `specs/` (optional) 8 | 9 | ## 3. Documentation 10 | - [ ] 3.1 Update README and template: "Validation checks only existing artifacts. Proposal-only changes are valid without spec deltas." 11 | 12 | ## 4. Tests 13 | - [ ] 4.1 Add test: proposal-only change passes validation without deltas 14 | - [ ] 4.2 Add test: specs present but zero parsed deltas → ERROR 15 | - [ ] 4.3 Add test: specs present with proper deltas → valid 16 | 17 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-add-non-interactive-init-options/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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. 3 | 4 | ## What Changes 5 | - Replace the multiple flag design with a single `--tools` option that accepts `all`, `none`, or a comma-separated list of tool IDs 6 | - Update InitCommand to bypass interactive prompts when `--tools` is supplied and apply single-flag validation rules 7 | - Document the non-interactive behavior via the CLI init spec delta (scenarios for `all`, `none`, list parsing, and invalid entries) 8 | - Generate CLI help text dynamically from `AI_TOOLS` so supported tools stay in sync 9 | 10 | ## Impact 11 | - Affected specs: `specs/cli-init/spec.md` 12 | - Affected code: `src/cli/index.ts`, `src/core/init.ts` 13 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-fix-update-tool-selection/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Update Update Command 4 | - [x] Remove hardcoded CLAUDE.md update from `src/core/update.ts` 5 | - [x] Add logic to check for existing AI tool configuration files 6 | - [x] Update only existing files using their appropriate configurators 7 | - [x] Iterate through all registered configurators to check for existing files 8 | 9 | ## 2. Update Configurator Registry 10 | - [x] Add method to get all configurators for update command 11 | - [x] Ensure each configurator can check if its file exists 12 | 13 | ## 3. Add Tests 14 | - [x] Test update command with only CLAUDE.md present 15 | - [x] Test update command with no AI tool files present 16 | - [x] Test update command with multiple AI tool files present 17 | - [x] Test that update never creates new AI tool files 18 | 19 | ## 4. Update Documentation 20 | - [x] Update README to clarify team-friendly behavior 21 | - [x] Document that update only modifies existing files -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-update-agent-file-name/specs/cli-update/spec.md: -------------------------------------------------------------------------------- 1 | ## MODIFIED Requirements 2 | 3 | ### Requirement: Update Behavior 4 | The update command SHALL update OpenSpec instruction files to the latest templates in a team-friendly manner. 5 | 6 | #### Scenario: Running update command 7 | - **WHEN** a user runs `openspec update` 8 | - **THEN** replace `openspec/AGENTS.md` with the latest template 9 | 10 | ### Requirement: File Handling 11 | The update command SHALL handle file updates in a predictable and safe manner. 12 | 13 | #### Scenario: Updating files 14 | - **WHEN** updating files 15 | - **THEN** completely replace `openspec/AGENTS.md` with the latest template 16 | 17 | ### Requirement: Core Files Always Updated 18 | The update command SHALL always update the core OpenSpec files and display an ASCII-safe success message. 19 | 20 | #### Scenario: Successful update 21 | - **WHEN** the update completes successfully 22 | - **THEN** replace `openspec/AGENTS.md` with the latest template 23 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-update-cli-init-root-agents/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Implementation 2 | - [x] 1.1 Refactor `openspec init` to always generate the root `AGENTS.md` stub (initial run and extend mode) via shared helper logic. 3 | - [x] 1.2 Rework the AI tool selection wizard to surface "Natively supported" vs "Other tools" groupings and make the stub non-optional. 4 | - [x] 1.3 Update CLI messaging, templates, and configurators so the new flow stays in sync across init and update commands. 5 | - [x] 1.4 Refresh unit/integration tests to cover the unconditional stub and the regrouped prompt layout. 6 | - [x] 1.5 Update documentation, README snippets, and CHANGELOG entries that mention the opt-in `AGENTS.md` experience. 7 | 8 | ## 2. Validation 9 | - [x] 2.1 Run `pnpm test` targeting CLI init/update suites. 10 | - [x] 2.2 Execute `openspec validate update-cli-init-root-agents --strict`. 11 | - [x] 2.3 Perform a manual smoke test: run `openspec init` in a temp directory, confirm stub + grouped prompts, rerun in extend mode. 12 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-add-multi-agent-init/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Extend Init Guard 4 | - [x] 1.1 Detect existing OpenSpec structures at the start of `openspec init` and enter an extend mode instead of failing. 5 | - [x] 1.2 Log that core scaffolding will be skipped while still protecting against missing write permissions. 6 | 7 | ## 2. Update AI Tool Selection 8 | - [x] 2.1 Present AI tool choices even in extend mode, indicating which tools are already configured. 9 | - [x] 2.2 Ensure disabled "coming soon" tools remain non-selectable. 10 | 11 | ## 3. Generate Additional Tool Files 12 | - [x] 3.1 Create configuration files for newly selected tools while leaving untouched tools unaffected apart from marker-managed sections. 13 | - [x] 3.2 Summarize created, refreshed, and skipped tools before exiting with the appropriate code. 14 | 15 | ## 4. Verification 16 | - [x] 4.1 Add tests covering rerunning `openspec init` to add another tool and the scenario where the user declines to add anything. 17 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-update-cli-init-enter-selection/specs/cli-init/spec.md: -------------------------------------------------------------------------------- 1 | ## MODIFIED Requirements 2 | ### Requirement: Interactive Mode 3 | The command SHALL provide an interactive menu for AI tool selection with clear navigation instructions. 4 | #### Scenario: Displaying interactive menu 5 | - **WHEN** run in fresh or extend mode 6 | - **THEN** present a looping select menu that lets users toggle tools with Space and review selections with Enter 7 | - **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 8 | - **AND** label already configured tools with "(already configured)" while keeping disabled options marked "coming soon" 9 | - **AND** change the prompt copy in extend mode to "Which AI tools would you like to add or refresh?" 10 | - **AND** display inline instructions clarifying that Space toggles tools and Enter selects the highlighted tool before reviewing selections 11 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-structured-spec-format/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Update OpenSpec Conventions Spec 2 | 3 | - [x] 1.1 Add "Specification Format" section to openspec-conventions 4 | - [x] 1.2 Document structured format with Requirement/Scenario headers 5 | - [x] 1.3 Define bold keyword usage (WHEN/THEN/AND) for scenarios 6 | - [x] 1.4 Include examples demonstrating the format within the spec itself 7 | 8 | ## 2. Update Documentation 9 | 10 | - [x] 2.1 Update the "Why This Approach" section with structured format benefits 11 | - [x] 2.2 Ensure spec follows its own format as a demonstration 12 | 13 | ## 3. Update Existing Specs 14 | 15 | - [x] 3.1 Update cli-init spec to use structured format in Behavior section 16 | - [x] 3.2 Update cli-list spec to use structured format in Behavior section 17 | - [x] 3.3 Update cli-update spec to use structured format in Behavior section 18 | - [x] 3.4 Update cli-diff spec to use structured format in Behavior section 19 | - [x] 3.5 Update cli-archive spec to use structured format in Behavior section -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-improve-cli-e2e-plan/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Phase 1 – Stabilize Local Spawn Coverage 2 | - [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. 3 | - [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. 4 | - [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. 5 | 6 | ## 2. Phase 2 – Expand Cross-Shell Validation 7 | - [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. 8 | - [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. 9 | 10 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/design.md: -------------------------------------------------------------------------------- 1 | # Design: Verb–Noun CLI Structure Adoption 2 | 3 | ## Overview 4 | 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. 5 | 6 | ## Decisions 7 | 8 | 1. Keep routing centralized in `src/cli/index.ts`. 9 | 2. Add `--specs`/`--changes` to `openspec list`, with `--changes` as default. 10 | 3. Show deprecation warnings for `openspec change list` and, more generally, for any `openspec change ...` and `openspec spec ...` subcommands. 11 | 4. Do not change `show`/`validate` behavior beyond help text; they already support `--type` for disambiguation. 12 | 13 | ## Backward Compatibility 14 | All noun-based commands continue to work with clear deprecation warnings directing users to verb-first equivalents. 15 | 16 | ## Out of Scope 17 | JSON output parity for `openspec list` across modes and `show --specs/--changes` discovery are follow-ups. 18 | 19 | 20 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/specs/cli-change/spec.md: -------------------------------------------------------------------------------- 1 | # CLI Change Command Spec 2 | 3 | ## ADDED Requirements 4 | 5 | ### Requirement: Interactive validation selection 6 | 7 | The change validate command SHALL support interactive selection when no change name is provided. 8 | 9 | #### Scenario: Interactive change selection for validation 10 | 11 | - **WHEN** executing `openspec change validate` without arguments 12 | - **THEN** display an interactive list of available changes 13 | - **AND** allow the user to select a change to validate 14 | - **AND** validate the selected change 15 | 16 | #### Scenario: Non-interactive fallback keeps current behavior 17 | 18 | - **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0` 19 | - **WHEN** executing `openspec change validate` without a change name 20 | - **THEN** do not prompt interactively 21 | - **AND** print the existing hint including available change IDs 22 | - **AND** set `process.exitCode = 1` -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-improve-validate-error-messages/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Enhance validation messages 2 | - [x] 1.1 Add remediation guidance for "No deltas found" 3 | - [x] 1.2 Include file path and structured path in all issues 4 | - [x] 1.3 Improve messages for missing required sections (Spec, Change) 5 | - [x] 1.4 Detect likely misformatted scenarios and warn with conversion example 6 | - [x] 1.5 Add "Next steps" footer for non-JSON invalid output 7 | 8 | ## 2. Update constants and helpers 9 | - [x] 2.1 Centralize guidance snippets in `VALIDATION_MESSAGES` 10 | - [x] 2.2 Provide minimal skeleton examples for missing sections 11 | 12 | ## 3. Parser integration 13 | - [x] 3.1 Capture parser-thrown errors and wrap with richer context 14 | - [x] 3.2 Add file/section references to surfaced parser errors 15 | 16 | ## 4. Tests 17 | - [x] 4.1 Unit tests for validator message composition 18 | - [x] 4.2 CLI integration tests for human-readable output (with footer) 19 | - [x] 4.3 JSON mode tests (structure unchanged, content enriched) 20 | 21 | 22 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-fix-update-tool-selection/specs/cli-update/spec.md: -------------------------------------------------------------------------------- 1 | ## ADDED Requirements 2 | 3 | ### Requirement: Tool-Agnostic Updates 4 | 5 | The update command SHALL update only existing AI tool configuration files and SHALL NOT create new ones. 6 | 7 | #### Scenario: Updating existing tool files 8 | 9 | - **WHEN** a user runs `openspec update` 10 | - **THEN** update each AI tool configuration file that exists (e.g., CLAUDE.md, COPILOT.md) 11 | - **AND** do not create missing tool configuration files 12 | - **AND** preserve user content outside OpenSpec markers 13 | 14 | ### Requirement: Core Files Always Updated 15 | 16 | The update command SHALL always update the core OpenSpec files and display an ASCII-safe success message. 17 | 18 | #### Scenario: Successful update 19 | 20 | - **WHEN** the update completes successfully 21 | - **THEN** replace `openspec/README.md` with the latest template 22 | - **AND** update existing AI tool configuration files within markers 23 | - **AND** display the message: "Updated OpenSpec instructions" -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-improve-agent-instruction-usability/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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. 3 | 4 | ## What Changes 5 | - Restructure `openspec/AGENTS.md` so file formats and scaffold templates appear in a top-level quick-reference section before workflow prose. 6 | - Embed copy/paste templates for `proposal.md`, `tasks.md`, `design.md`, and spec deltas alongside inline examples within the workflow steps. 7 | - Add a pre-validation checklist that highlights the most common formatting pitfalls before running `openspec validate`. 8 | - Split content into beginner vs. advanced sections to progressively disclose complexity while keeping advanced guidance accessible. 9 | 10 | ## Impact 11 | - Affected specs: `specs/docs-agent-instructions` 12 | - Affected code: `openspec/AGENTS.md`, `docs/` 13 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-01-13-add-list-command/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Core Implementation 4 | - [x] 1.1 Create `src/core/list.ts` with list logic 5 | - [x] 1.1.1 Implement directory scanning (exclude archive/) 6 | - [x] 1.1.2 Implement task counting from tasks.md files 7 | - [x] 1.1.3 Format output as simple table 8 | - [x] 1.2 Add list command to CLI in `src/cli/index.ts` 9 | - [x] 1.2.1 Register `openspec list` command 10 | - [x] 1.2.2 Connect to list.ts implementation 11 | 12 | ## 2. Error Handling 13 | - [x] 2.1 Handle missing openspec/changes/ directory 14 | - [x] 2.2 Handle changes without tasks.md files 15 | - [x] 2.3 Handle empty changes directory 16 | 17 | ## 3. Testing 18 | - [x] 3.1 Add tests for list functionality 19 | - [x] 3.1.1 Test with multiple changes 20 | - [x] 3.1.2 Test with completed changes 21 | - [x] 3.1.3 Test with no changes 22 | - [x] 3.1.4 Test error conditions 23 | 24 | ## 4. Documentation 25 | - [x] 4.1 Update CLI help text with list command 26 | - [x] 4.2 Add list command to README if applicable -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-interactive-show-command/specs/cli-spec/spec.md: -------------------------------------------------------------------------------- 1 | # CLI Spec Command Spec 2 | 3 | ## ADDED Requirements 4 | 5 | ### Requirement: Interactive spec show 6 | 7 | The spec show command SHALL support interactive selection when no spec-id is provided. 8 | 9 | #### Scenario: Interactive spec selection for show 10 | 11 | - **WHEN** executing `openspec spec show` without arguments 12 | - **THEN** display an interactive list of available specs 13 | - **AND** allow the user to select a spec to show 14 | - **AND** display the selected spec content 15 | - **AND** maintain all existing show options (--json, --requirements, --no-scenarios, -r) 16 | 17 | #### Scenario: Non-interactive fallback keeps current behavior 18 | 19 | - **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0` 20 | - **WHEN** executing `openspec spec show` without a spec-id 21 | - **THEN** do not prompt interactively 22 | - **AND** print the existing error message for missing spec-id 23 | - **AND** set non-zero exit code -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-enhance-validation-error-messages/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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. 3 | 4 | ## What Changes 5 | - Extend `openspec validate` error reporting so each failure names the exact header, file, and expected structure, including concrete examples of compliant Markdown. 6 | - Tailor messages for the most common mistakes (missing delta sections, absent descriptive requirement text, missing scenarios) with actionable fixes and suggested debug commands. 7 | - Update docs/help output so the improved messaging is discoverable (e.g., `--help`, troubleshooting section). 8 | - Add regression coverage to lock in the richer messaging for the top validation paths. 9 | 10 | ## Impact 11 | - Affected specs: `specs/cli-validate` 12 | - Affected code: `src/commands/validate.ts`, `src/core/validation`, `docs/` 13 | -------------------------------------------------------------------------------- /openspec/changes/add-scaffold-command/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | Manual setup for new changes leads to formatting mistakes in spec deltas and slows agents who must recreate the same file skeletons for every proposal. A built-in scaffold command will generate compliant templates so assistants can focus on the change content instead of structure. 3 | 4 | ## What Changes 5 | - Add an `openspec scaffold ` CLI command that creates a change directory (if it does not already exist) with validated `proposal.md`, `tasks.md`, and spec delta templates. 6 | - Update CLI documentation and quick-reference guidance so agents discover the scaffold workflow before drafting files manually, including reminders on when to create spec deltas. 7 | - Add automated coverage (unit/integ tests) to ensure the command respects naming rules, copies templates correctly, fails for existing directories, and produces output that passes `openspec validate --strict` untouched. 8 | 9 | ## Impact 10 | - Affected specs: `specs/cli-scaffold` 11 | - Affected code: `src/cli/index.ts`, `src/commands`, `docs/` 12 | -------------------------------------------------------------------------------- /src/core/configurators/slash/gemini.ts: -------------------------------------------------------------------------------- 1 | import { TomlSlashCommandConfigurator } from './toml-base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.gemini/commands/openspec/proposal.toml', 6 | apply: '.gemini/commands/openspec/apply.toml', 7 | archive: '.gemini/commands/openspec/archive.toml' 8 | }; 9 | 10 | const DESCRIPTIONS: Record = { 11 | proposal: 'Scaffold a new OpenSpec change and validate strictly.', 12 | apply: 'Implement an approved OpenSpec change and keep tasks in sync.', 13 | archive: 'Archive a deployed OpenSpec change and update specs.' 14 | }; 15 | 16 | export class GeminiSlashCommandConfigurator extends TomlSlashCommandConfigurator { 17 | readonly toolId = 'gemini'; 18 | readonly isAvailable = true; 19 | 20 | protected getRelativePath(id: SlashCommandId): string { 21 | return FILE_PATHS[id]; 22 | } 23 | 24 | protected getDescription(id: SlashCommandId): string { 25 | return DESCRIPTIONS[id]; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/specs/cli-spec/spec.md: -------------------------------------------------------------------------------- 1 | # CLI Spec Command Spec 2 | 3 | ## ADDED Requirements 4 | 5 | ### Requirement: Interactive spec validation 6 | 7 | The spec validate command SHALL support interactive selection when no spec-id is provided. 8 | 9 | #### Scenario: Interactive spec selection for validation 10 | 11 | - **WHEN** executing `openspec spec validate` without arguments 12 | - **THEN** display an interactive list of available specs 13 | - **AND** allow the user to select a spec to validate 14 | - **AND** validate the selected spec 15 | - **AND** maintain all existing validation options (--strict, --json) 16 | 17 | #### Scenario: Non-interactive fallback keeps current behavior 18 | 19 | - **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0` 20 | - **WHEN** executing `openspec spec validate` without a spec-id 21 | - **THEN** do not prompt interactively 22 | - **AND** print the existing error message for missing spec-id 23 | - **AND** set non-zero exit code -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-interactive-show-command/specs/cli-change/spec.md: -------------------------------------------------------------------------------- 1 | # CLI Change Command Spec 2 | 3 | ## ADDED Requirements 4 | 5 | ### Requirement: Interactive show selection 6 | 7 | The change show command SHALL support interactive selection when no change name is provided. 8 | 9 | #### Scenario: Interactive change selection for show 10 | 11 | - **WHEN** executing `openspec change show` without arguments 12 | - **THEN** display an interactive list of available changes 13 | - **AND** allow the user to select a change to show 14 | - **AND** display the selected change content 15 | - **AND** maintain all existing show options (--json, --deltas-only) 16 | 17 | #### Scenario: Non-interactive fallback keeps current behavior 18 | 19 | - **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0` 20 | - **WHEN** executing `openspec change show` without a change name 21 | - **THEN** do not prompt interactively 22 | - **AND** print the existing hint including available change IDs 23 | - **AND** set `process.exitCode = 1` -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-22-add-cline-support/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Implementation 2 | - [x] 1.1 Create ClineSlashCommandConfigurator class in src/core/configurators/slash/cline.ts 3 | - [x] 1.2 Create ClineConfigurator class in src/core/configurators/cline.ts 4 | - [x] 1.3 Create cline-template.ts for template exports 5 | - [x] 1.4 Define file paths for Cline rules (.clinerules/) 6 | - [x] 1.5 Create Cline-specific frontmatter (Markdown heading format) 7 | - [x] 1.6 Register Cline in slash/registry.ts 8 | - [x] 1.7 Register Cline in configurators/registry.ts 9 | - [x] 1.8 Add Cline to AI_TOOLS in config.ts 10 | - [x] 1.9 Add getClineTemplate() to templates/index.ts 11 | - [x] 1.10 Update README with Cline documentation 12 | 13 | ## 2. Testing 14 | - [x] 2.1 Add init tests for CLINE.md creation and updates 15 | - [x] 2.2 Add init tests for .clinerules/ file creation 16 | - [x] 2.3 Add update tests for CLINE.md updates 17 | - [x] 2.4 Add update tests for .clinerules/ file refreshes 18 | - [x] 2.5 Test integration with openspec init --tools cline 19 | - [x] 2.6 Verify all 225 tests pass 20 | -------------------------------------------------------------------------------- /openspec/changes/fix-cline-workflows-implementation/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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/`. 3 | 4 | ## What Changes 5 | - Update ClineSlashCommandConfigurator to use `.clinerules/workflows/` paths instead of `.clinerules/` paths 6 | - Update all tests to expect the correct workflow file locations 7 | - Update README.md documentation to reflect workflows instead of rules 8 | - **BREAKING**: Existing Cline users will need to re-run `openspec init` to get the corrected workflow files 9 | 10 | ## Impact 11 | - Affected specs: cli-init (corrected Cline workflow paths) 12 | - Affected code: `src/core/configurators/slash/cline.ts`, test files, README.md 13 | - Modified files: `.clinerules/workflows/openspec-*.md` (moved from `.clinerules/openspec-*.md`) 14 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-22-add-factory-slash-commands/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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. 3 | 4 | ## What Changes 5 | - Extend the native tool registry so Factory/Droid appears alongside other slash-command integrations during `openspec init`. 6 | - Add shared templates that generate the three Factory custom commands (proposal, apply, archive) and wrap them in OpenSpec markers for safe refreshes. 7 | - Update the init and update command flows so they create or refresh Factory command files when the tool is selected or already present. 8 | - Refresh CLI specs to document the Factory support and align validation expectations. 9 | 10 | ## Impact 11 | - Affected specs: `specs/cli-init`, `specs/cli-update` 12 | - Affected code (expected): tool registry, slash-command template manager, init/update command helpers, documentation snippets 13 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-skip-specs-archive-option/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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). 3 | 4 | ## What Changes 5 | - Add new `--skip-specs` flag to the archive command that bypasses all spec update operations 6 | - Fix confirmation behavior: when users decline spec updates interactively, proceed with archiving instead of cancelling the entire operation 7 | - When `--skip-specs` flag is used, skip both the spec discovery and update confirmation steps entirely 8 | - Display clear message when specs are skipped (either via flag or user choice) 9 | - Flag can be combined with existing `--yes` flag for fully automated archiving without spec updates 10 | 11 | ## Impact 12 | - Affected specs: cli-archive 13 | - Affected code: src/core/archive.ts, src/cli/index.ts -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-add-kilocode-workflows/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. CLI wiring 2 | - [x] 1.1 Add Kilo Code to the selectable AI tools in `openspec init`, including "already configured" detection and success summaries. 3 | - [x] 1.2 Register a `KiloCodeSlashCommandConfigurator` alongside other slash-command tools. 4 | 5 | ## 2. Workflow generation 6 | - [x] 2.1 Implement the configurator so it creates `.kilocode/workflows/` (if needed) and writes `openspec-{proposal,apply,archive}.md` with OpenSpec markers. 7 | - [x] 2.2 Reuse the shared slash-command bodies without front matter; verify resulting files stay Markdown-only with no extra metadata. 8 | 9 | ## 3. Update support 10 | - [x] 3.1 Ensure `openspec update` refreshes existing Kilo Code workflows while skipping ones that are absent. 11 | - [x] 3.2 Add regression coverage confirming marker content is replaced (not duplicated) during updates. 12 | 13 | ## 4. Documentation 14 | - [x] 4.1 Update README / docs to note Kilo Code workflow support and path (`.kilocode/workflows/`). 15 | - [x] 4.2 Mention the integration in CHANGELOG or release notes if applicable. 16 | -------------------------------------------------------------------------------- /openspec/changes/add-antigravity-support/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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. 3 | 4 | ## What Changes 5 | - 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. 6 | - Ensure `openspec update` refreshes the body of any existing Antigravity workflows inside `.agent/workflows/` without creating missing files, mirroring the Windsurf behavior. 7 | - Share e2e/template coverage confirming the generator writes the proper directory, filename casing, and frontmatter format so Antigravity picks up the workflows. 8 | 9 | ## Impact 10 | - Affected specs: `specs/cli-init`, `specs/cli-update` 11 | - Expected code: CLI init/update tool registries, slash-command templates, associated tests 12 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-zod-validation/proposal.md: -------------------------------------------------------------------------------- 1 | # Change: Add Zod Runtime Validation 2 | 3 | ## Why 4 | 5 | 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. 6 | 7 | ## What Changes 8 | 9 | - Enhance existing `spec validate` and `change validate` commands with strict Zod validation 10 | - Add validation to the archive command to ensure changes are valid before applying 11 | - Add validation to the diff command to ensure changes are well-formed 12 | - Provide detailed validation reports in JSON format 13 | - Add `--strict` mode that fails on warnings 14 | 15 | ## Impact 16 | 17 | - **Affected specs**: cli-spec, cli-change, cli-archive, cli-diff 18 | - **Affected code**: 19 | - src/commands/spec.ts (enhance validate subcommand) 20 | - src/commands/change.ts (enhance validate subcommand) 21 | - src/core/archive.ts (add pre-archive validation) 22 | - src/core/diff.ts (add validation check) -------------------------------------------------------------------------------- /openspec/changes/archive/2025-12-20-add-global-config-dir/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 3 | 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. 4 | 5 | ## What Changes 6 | 7 | - Add new `src/core/global-config.ts` module with: 8 | - Path resolution following XDG Base Directory spec (`$XDG_CONFIG_HOME/openspec/` or fallback) 9 | - Cross-platform support (Unix, macOS, Windows) 10 | - Lazy config loading with sensible defaults 11 | - TypeScript types for config shape 12 | - Export a global config directory path getter for future use (workflows, templates, cache) 13 | - Initial config schema supports 1-2 settings/feature flags only 14 | 15 | ## Impact 16 | 17 | - Affected specs: New `global-config` capability (no existing specs modified) 18 | - Affected code: 19 | - New `src/core/global-config.ts` 20 | - Update `src/core/index.ts` to export new module 21 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-05-initialize-typescript-project/tasks.md: -------------------------------------------------------------------------------- 1 | # Tasks 2 | 3 | ## 1. Project Configuration 4 | - [x] 1.1 Create package.json with project metadata, scripts, and ESM configuration 5 | - [x] 1.2 Configure TypeScript with tsconfig.json for ESM output 6 | - [x] 1.3 Add .gitignore for Node.js/TypeScript projects 7 | - [x] 1.4 Set Node.js engine requirement to >=20.19.0 8 | 9 | ## 2. Directory Structure 10 | - [x] 2.1 Create src/ directory for source code 11 | - [x] 2.2 Create src/cli/ for CLI commands 12 | - [x] 2.3 Create src/core/ for core OpenSpec logic 13 | - [x] 2.4 Create src/utils/ for shared utilities 14 | 15 | ## 3. Build Configuration 16 | - [x] 3.1 Create build.js for native TypeScript compilation 17 | - [x] 3.2 Configure development scripts (build, dev) 18 | - [x] 3.3 Set up package entry points with ESM exports 19 | - [x] 3.4 Configure proper file extensions handling for ESM 20 | 21 | ## 4. Initial Dependencies 22 | - [x] 4.1 Add TypeScript as dev dependency 23 | - [x] 4.2 Add commander for CLI framework 24 | - [x] 4.3 Add @inquirer/prompts for user interaction 25 | - [x] 4.4 Add necessary type definitions -------------------------------------------------------------------------------- /openspec/changes/add-scaffold-command/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. CLI scaffolding command 2 | - [ ] 1.1 Register an `openspec scaffold` command in the CLI entrypoint with `change-id` argument validation. 3 | - [ ] 1.2 Implement generator logic that copies the default change template bundle (`proposal.md`, `tasks.md`, optional `design.md`, `specs/README.md`) into `openspec/changes//`, creating the directory tree in a single pass. 4 | - [ ] 1.3 Detect when `openspec/changes//` already exists and exit with a clear error instead of overwriting user files. 5 | 6 | ## 2. Templates and documentation 7 | - [ ] 2.1 Update `openspec/AGENTS.md` quick reference so agents see `openspec scaffold` before drafting files manually. 8 | - [ ] 2.2 Refresh CLI docs/README/help text to mention the scaffold workflow, template bundle contents, and when to add spec deltas manually. 9 | 10 | ## 3. Test coverage 11 | - [ ] 3.1 Add unit tests covering name validation, template copying, and existing-directory failures. 12 | - [ ] 3.2 Add integration coverage ensuring a freshly scaffolded change (without deltas) passes `openspec validate --strict` until the author customizes it. 13 | -------------------------------------------------------------------------------- /src/core/configurators/slash/antigravity.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.agent/workflows/openspec-proposal.md', 6 | apply: '.agent/workflows/openspec-apply.md', 7 | archive: '.agent/workflows/openspec-archive.md' 8 | }; 9 | 10 | const DESCRIPTIONS: Record = { 11 | proposal: 'Scaffold a new OpenSpec change and validate strictly.', 12 | apply: 'Implement an approved OpenSpec change and keep tasks in sync.', 13 | archive: 'Archive a deployed OpenSpec change and update specs.' 14 | }; 15 | 16 | export class AntigravitySlashCommandConfigurator extends SlashCommandConfigurator { 17 | readonly toolId = 'antigravity'; 18 | readonly isAvailable = true; 19 | 20 | protected getRelativePath(id: SlashCommandId): string { 21 | return FILE_PATHS[id]; 22 | } 23 | 24 | protected getFrontmatter(id: SlashCommandId): string | undefined { 25 | const description = DESCRIPTIONS[id]; 26 | return `---\ndescription: ${description}\n---`; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-improve-init-onboarding/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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. 3 | 4 | ## What Changes 5 | - Allow selecting multiple assistants during `openspec init`, including refreshing existing configurations in a single run. 6 | - Provide richer onboarding copy that summarizes which tool files were created or refreshed and guides users on next steps for each assistant. 7 | - Align generated AI-instruction content and specs so CLAUDE.md and AGENTS.md share the same OpenSpec guidance. 8 | - Update specs and tests to cover the multi-select prompt, improved summaries, and extend-mode coordination. 9 | 10 | ## Impact 11 | - Specs: `cli-init` 12 | - Code: `src/core/init.ts`, `src/core/config.ts`, `src/core/templates/*`, `src/core/configurators/*` 13 | - Tests: `test/core/init.test.ts`, `test/core/update.test.ts` 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 OpenSpec Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-improve-deterministic-tests/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Test Isolation 4 | - [x] 1.1 Create temp fixture roots per suite (openspec/changes, openspec/specs) 5 | - [x] 1.2 Use process.chdir to temp root within tests 6 | - [x] 1.3 Restore original cwd and clean temp dirs after each 7 | 8 | ## 2. Deterministic Discovery 9 | - [x] 2.1 Implement getActiveChangeIds(root?) to only include dirs with proposal.md 10 | - [x] 2.2 Implement getSpecIds(root?) to only include dirs with spec.md 11 | - [x] 2.3 Return sorted results to avoid fs.readdir ordering variance 12 | 13 | ## 3. Command Integration 14 | - [x] 3.1 Ensure change/show/validate rely on cwd and discovery helpers 15 | - [x] 3.2 Keep runtime behavior unchanged for end users 16 | 17 | ## 4. Validation 18 | - [x] 4.1 Convert affected command tests (show, spec, validate, change) to isolated fixtures 19 | - [x] 4.2 Verify tests pass consistently across environments 20 | - [x] 4.3 Confirm no reads from real repo state during tests 21 | 22 | ## 5. Optional (Not Needed Now) 23 | - [x] 5.1 Add optional root param to discovery helpers (default process.cwd()) 24 | 25 | 26 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-06-adopt-future-state-storage/proposal.md: -------------------------------------------------------------------------------- 1 | # Adopt Future State Storage for OpenSpec Changes 2 | 3 | ## Why 4 | 5 | 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. 6 | 7 | ## What Changes 8 | 9 | - Change from storing diffs (`patches/[capability]/spec.md.diff`) to storing complete future state (`specs/[capability]/spec.md`) 10 | - Update all documentation to reflect new storage format 11 | - Migrate existing `add-init-command` change to new format 12 | - Add new `openspec-conventions` capability to document these conventions 13 | 14 | 15 | 16 | ## Impact 17 | 18 | - Affected specs: New `openspec-conventions` capability 19 | - Affected code: 20 | - openspec/README.md (lines 85-108) 21 | - docs/PRD.md (lines 376-382, 778-783) 22 | - docs/openspec-walkthrough.md (lines 58-62, 112-126) 23 | - openspec/changes/add-init-command/ (migration needed) 24 | 25 | -------------------------------------------------------------------------------- /src/core/configurators/slash/roocode.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const NEW_FILE_PATHS: Record = { 5 | proposal: '.roo/commands/openspec-proposal.md', 6 | apply: '.roo/commands/openspec-apply.md', 7 | archive: '.roo/commands/openspec-archive.md' 8 | }; 9 | 10 | export class RooCodeSlashCommandConfigurator extends SlashCommandConfigurator { 11 | readonly toolId = 'roocode'; 12 | readonly isAvailable = true; 13 | 14 | protected getRelativePath(id: SlashCommandId): string { 15 | return NEW_FILE_PATHS[id]; 16 | } 17 | 18 | protected getFrontmatter(id: SlashCommandId): string | undefined { 19 | const descriptions: Record = { 20 | proposal: 'Scaffold a new OpenSpec change and validate strictly.', 21 | apply: 'Implement an approved OpenSpec change and keep tasks in sync.', 22 | archive: 'Archive a deployed OpenSpec change and update specs.' 23 | }; 24 | const description = descriptions[id]; 25 | return `# OpenSpec: ${id.charAt(0).toUpperCase() + id.slice(1)}\n\n${description}`; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/core/configurators/slash/windsurf.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.windsurf/workflows/openspec-proposal.md', 6 | apply: '.windsurf/workflows/openspec-apply.md', 7 | archive: '.windsurf/workflows/openspec-archive.md' 8 | }; 9 | 10 | export class WindsurfSlashCommandConfigurator extends SlashCommandConfigurator { 11 | readonly toolId = 'windsurf'; 12 | readonly isAvailable = true; 13 | 14 | protected getRelativePath(id: SlashCommandId): string { 15 | return FILE_PATHS[id]; 16 | } 17 | 18 | protected getFrontmatter(id: SlashCommandId): string | undefined { 19 | const descriptions: Record = { 20 | proposal: 'Scaffold a new OpenSpec change and validate strictly.', 21 | apply: 'Implement an approved OpenSpec change and keep tasks in sync.', 22 | archive: 'Archive a deployed OpenSpec change and update specs.' 23 | }; 24 | const description = descriptions[id]; 25 | return `---\ndescription: ${description}\nauto_execution_mode: 3\n---`; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-slim-root-agents-file/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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. 3 | 4 | ## What Changes 5 | - Keep generating the complete template in `openspec/AGENTS.md` during `openspec init` and follow-up updates. 6 | - 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`. 7 | - Add a dedicated stub template so both the init and update flows reuse the same minimal copy instructions. 8 | - Update CLI tests and documentation to reflect the new root-level messaging and ensure the OpenSpec marker block still protects future updates. 9 | 10 | ## Impact 11 | - Affected specs: `cli-init`, `cli-update` 12 | - Affected code: `src/core/init.ts`, `src/core/update.ts`, `src/core/templates/agents-template.ts` 13 | - Update assets/readmes that mention the root `AGENTS.md` contents to reference the new stub message. 14 | -------------------------------------------------------------------------------- /src/core/configurators/slash/cline.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.clinerules/workflows/openspec-proposal.md', 6 | apply: '.clinerules/workflows/openspec-apply.md', 7 | archive: '.clinerules/workflows/openspec-archive.md' 8 | }; 9 | 10 | export class ClineSlashCommandConfigurator extends SlashCommandConfigurator { 11 | readonly toolId = 'cline'; 12 | readonly isAvailable = true; 13 | 14 | protected getRelativePath(id: SlashCommandId): string { 15 | return FILE_PATHS[id]; 16 | } 17 | 18 | protected getFrontmatter(id: SlashCommandId): string | undefined { 19 | const descriptions: Record = { 20 | proposal: 'Scaffold a new OpenSpec change and validate strictly.', 21 | apply: 'Implement an approved OpenSpec change and keep tasks in sync.', 22 | archive: 'Archive a deployed OpenSpec change and update specs.' 23 | }; 24 | const description = descriptions[id]; 25 | return `# OpenSpec: ${id.charAt(0).toUpperCase() + id.slice(1)}\n\n${description}`; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/specs/openspec-conventions/spec.md: -------------------------------------------------------------------------------- 1 | # Delta: OpenSpec Conventions — Verb–Noun CLI Design 2 | 3 | ## ADDED Requirements 4 | 5 | ### Requirement: Verb–Noun CLI Command Structure 6 | OpenSpec CLI design SHALL use verbs as top-level commands with nouns provided as arguments or flags for scoping. 7 | 8 | #### Scenario: Verb-first command discovery 9 | - **WHEN** a user runs a command like `openspec list` 10 | - **THEN** the verb communicates the action clearly 11 | - **AND** nouns refine scope via flags or arguments (e.g., `--changes`, `--specs`) 12 | 13 | #### Scenario: Backward compatibility for noun commands 14 | - **WHEN** users run noun-prefixed commands such as `openspec spec ...` or `openspec change ...` 15 | - **THEN** the CLI SHALL continue to support them for at least one release 16 | - **AND** display a deprecation warning that points to verb-first alternatives 17 | 18 | #### Scenario: Disambiguation guidance 19 | - **WHEN** item names are ambiguous between changes and specs 20 | - **THEN** `openspec show` and `openspec validate` SHALL accept `--type spec|change` 21 | - **AND** the help text SHALL document this clearly 22 | 23 | 24 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 3 | Currently, users must validate changes and specs individually by specifying each ID. This creates friction when: 4 | - Teams want to validate all changes/specs before a release 5 | - Developers need to ensure consistency across multiple related changes 6 | - Users run validation commands without arguments and receive errors instead of helpful guidance 7 | - The subcommand structure requires users to know in advance whether they're validating a change or spec 8 | 9 | ## What Changes 10 | 11 | - Add new top-level `validate` command with intuitive flags (--all, --changes, --specs) 12 | - Enhance existing `change validate` and `spec validate` to support interactive selection (backwards compatibility) 13 | - Interactive selection by default when no arguments provided 14 | - Support direct item validation: `openspec validate ` with automatic type detection 15 | 16 | ## Impact 17 | 18 | - New specs to create: cli-validate 19 | - Specs to enhance: cli-change, cli-spec (for backwards compatibility) 20 | - Affected code: src/cli/index.ts, src/commands/validate.ts (new), src/commands/spec.ts, src/commands/change.ts -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-interactive-show-command/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 3 | 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: 4 | - Users want to quickly view an item without remembering its type 5 | - Exploring the codebase requires switching between different show commands 6 | - Show commands without arguments return errors instead of helpful guidance 7 | 8 | ## What Changes 9 | 10 | - Add new top-level `show` command for displaying changes or specs with intelligent selection 11 | - Support direct item display: `openspec show ` with automatic type detection 12 | - Interactive selection when no arguments provided 13 | - Enhance existing `change show` and `spec show` to support interactive selection (backwards compatibility) 14 | - Maintain all existing format options (--json, --deltas-only, --requirements, etc.) 15 | 16 | ## Impact 17 | 18 | - New specs to create: cli-show 19 | - Specs to enhance: cli-change, cli-spec (for backwards compatibility) 20 | - Affected code: src/cli/index.ts, src/commands/show.ts (new), src/commands/spec.ts, src/commands/change.ts -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-add-agents-md-config/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Extend Init Workflow 4 | - [x] 1.1 Add an "AGENTS.md standard" option to the `openspec init` tool-selection prompt, respecting the existing UI conventions. 5 | - [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. 6 | 7 | ## 2. Enhance Update Command 8 | - [x] 2.1 Ensure `openspec update` writes the root `AGENTS.md` from the latest template (creating it if missing) alongside `openspec/AGENTS.md`. 9 | - [x] 2.2 Update success messaging and logging to reflect creation vs refresh of the AGENTS standard file. 10 | 11 | ## 3. Shared Template Handling 12 | - [x] 3.1 Refactor template utilities if necessary so both commands reuse the same content without duplication. 13 | - [x] 3.2 Add automated tests covering init/update flows for projects with and without an existing `AGENTS.md`, ensuring markers behave correctly. 14 | 15 | ## 4. Documentation 16 | - [x] 4.1 Update CLI specs and user-facing docs to describe AGENTS standard support. 17 | - [x] 4.2 Run `openspec validate add-agents-md-config --strict` and document any notable behavior changes. 18 | -------------------------------------------------------------------------------- /src/core/configurators/slash/github-copilot.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.github/prompts/openspec-proposal.prompt.md', 6 | apply: '.github/prompts/openspec-apply.prompt.md', 7 | archive: '.github/prompts/openspec-archive.prompt.md' 8 | }; 9 | 10 | const FRONTMATTER: Record = { 11 | proposal: `--- 12 | description: Scaffold a new OpenSpec change and validate strictly. 13 | --- 14 | 15 | $ARGUMENTS`, 16 | apply: `--- 17 | description: Implement an approved OpenSpec change and keep tasks in sync. 18 | --- 19 | 20 | $ARGUMENTS`, 21 | archive: `--- 22 | description: Archive a deployed OpenSpec change and update specs. 23 | --- 24 | 25 | $ARGUMENTS` 26 | }; 27 | 28 | export class GitHubCopilotSlashCommandConfigurator extends SlashCommandConfigurator { 29 | readonly toolId = 'github-copilot'; 30 | readonly isAvailable = true; 31 | 32 | protected getRelativePath(id: SlashCommandId): string { 33 | return FILE_PATHS[id]; 34 | } 35 | 36 | protected getFrontmatter(id: SlashCommandId): string { 37 | return FRONTMATTER[id]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/core/configurators/slash/auggie.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.augment/commands/openspec-proposal.md', 6 | apply: '.augment/commands/openspec-apply.md', 7 | archive: '.augment/commands/openspec-archive.md' 8 | }; 9 | 10 | const FRONTMATTER: Record = { 11 | proposal: `--- 12 | description: Scaffold a new OpenSpec change and validate strictly. 13 | argument-hint: feature description or request 14 | ---`, 15 | apply: `--- 16 | description: Implement an approved OpenSpec change and keep tasks in sync. 17 | argument-hint: change-id 18 | ---`, 19 | archive: `--- 20 | description: Archive a deployed OpenSpec change and update specs. 21 | argument-hint: change-id 22 | ---` 23 | }; 24 | 25 | export class AuggieSlashCommandConfigurator extends SlashCommandConfigurator { 26 | readonly toolId = 'auggie'; 27 | readonly isAvailable = true; 28 | 29 | protected getRelativePath(id: SlashCommandId): string { 30 | return FILE_PATHS[id]; 31 | } 32 | 33 | protected getFrontmatter(id: SlashCommandId): string { 34 | return FRONTMATTER[id]; 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-update-agent-file-name/proposal.md: -------------------------------------------------------------------------------- 1 | # Update Agent Instruction File Name 2 | 3 | ## Problem 4 | The agent instructions live in `openspec/README.md`, which clashes with conventional project README usage and creates confusion for tooling and contributors. 5 | 6 | ## Solution 7 | Rename the agent instruction file to `openspec/AGENTS.md` and update OpenSpec tooling to use the new filename: 8 | - `openspec init` generates `AGENTS.md` instead of `README.md` 9 | - Templates and code reference `AGENTS.md` 10 | - Specifications and documentation are updated accordingly 11 | 12 | ## Benefits 13 | - Clear separation from project documentation 14 | - Consistent naming with other agent instruction files 15 | - Simplifies tooling and project onboarding 16 | 17 | ## Implementation 18 | - Rename instruction file and template 19 | - Update CLI commands (`init`, `update`) to read/write `AGENTS.md` 20 | - Adjust specs and documentation to reference the new path 21 | 22 | ## Risks 23 | - Existing projects may still rely on `README.md` 24 | - Tooling may miss lingering references to the old filename 25 | 26 | ## Success Metrics 27 | - `openspec init` creates `openspec/AGENTS.md` 28 | - `openspec update` refreshes `AGENTS.md` 29 | - All specs reference `openspec/AGENTS.md` 30 | -------------------------------------------------------------------------------- /src/core/templates/project-template.ts: -------------------------------------------------------------------------------- 1 | export interface ProjectContext { 2 | projectName?: string; 3 | description?: string; 4 | techStack?: string[]; 5 | conventions?: string; 6 | } 7 | 8 | export const projectTemplate = (context: ProjectContext = {}) => `# ${context.projectName || 'Project'} Context 9 | 10 | ## Purpose 11 | ${context.description || '[Describe your project\'s purpose and goals]'} 12 | 13 | ## Tech Stack 14 | ${context.techStack?.length ? context.techStack.map(tech => `- ${tech}`).join('\n') : '- [List your primary technologies]\n- [e.g., TypeScript, React, Node.js]'} 15 | 16 | ## Project Conventions 17 | 18 | ### Code Style 19 | [Describe your code style preferences, formatting rules, and naming conventions] 20 | 21 | ### Architecture Patterns 22 | [Document your architectural decisions and patterns] 23 | 24 | ### Testing Strategy 25 | [Explain your testing approach and requirements] 26 | 27 | ### Git Workflow 28 | [Describe your branching strategy and commit conventions] 29 | 30 | ## Domain Context 31 | [Add domain-specific knowledge that AI assistants need to understand] 32 | 33 | ## Important Constraints 34 | [List any technical, business, or regulatory constraints] 35 | 36 | ## External Dependencies 37 | [Document key external services, APIs, or systems] 38 | `; -------------------------------------------------------------------------------- /openspec/changes/add-antigravity-support/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. CLI init support 2 | - [x] 1.1 Surface Antigravity in the native-tool picker (interactive + `--tools`) so it toggles alongside other IDEs. 3 | - [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. 4 | - [x] 1.3 Confirm workspace scaffolding covers missing directory creation and re-run scenarios so repeated init refreshes the managed block. 5 | 6 | ## 2. CLI update support 7 | - [x] 2.1 Detect existing Antigravity workflow files during `openspec update` and refresh only the managed body, skipping creation when files are missing. 8 | - [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. 9 | 10 | ## 3. Templates and tests 11 | - [x] 3.1 Add shared template entries for Antigravity that reuse the Windsurf copy but target `.agent/workflows` plus the description-only frontmatter requirement. 12 | - [x] 3.2 Expand automated coverage (unit or integration) verifying init and update produce the expected file paths and frontmatter + body markers for Antigravity. 13 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-add-slash-command-support/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Templates and Configurators 4 | - [x] 1.1 Create shared templates for the Proposal, Apply, and Archive commands with instructions for each workflow stage from `openspec/README.md`. 5 | - [x] 1.2 Implement a `SlashCommandConfigurator` base and tool-specific configurators for Claude Code and Cursor. 6 | 7 | ## 2. Claude Code Integration 8 | - [x] 2.1 Generate `.claude/commands/openspec/{proposal,apply,archive}.md` during `openspec init` using shared templates. 9 | - [x] 2.2 Update existing `.claude/commands/openspec/*` files during `openspec update`. 10 | 11 | ## 3. Cursor Integration 12 | - [x] 3.1 Generate `.cursor/commands/{openspec-proposal,openspec-apply,openspec-archive}.md` during `openspec init` using shared templates. 13 | - [x] 3.2 Update existing `.cursor/commands/*` files during `openspec update`. 14 | 15 | ## 4. Verification 16 | - [x] 4.1 Add tests verifying slash command files are created and updated correctly. 17 | 18 | ## 5. OpenCode Integration 19 | - [x] 5.1 Generate `.opencode/commands/{openspec-proposal,openspec-apply,openspec-archive}.md` during `openspec init` using shared templates. 20 | - [x] 5.2 Update existing `.opencode/commands/*` files during `openspec update`. 21 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-add-non-interactive-init-options/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. CLI Option Registration 2 | - [x] 1.1 Replace the multiple flag design with a single `--tools ` option supporting `all|none|a,b,c` and keep strict argument validation. 3 | - [x] 1.2 Populate the `--tools` help text dynamically from the `AI_TOOLS` registry. 4 | 5 | ## 2. InitCommand Modifications 6 | - [x] 2.1 Accept the single tools option in the InitCommand constructor and plumb it through existing flows. 7 | - [x] 2.2 Update tool selection logic to shortcut prompts for `all`, `none`, and explicit lists. 8 | - [x] 2.3 Fail fast with exit code 1 and a helpful message when the parsed list contains unsupported tool IDs. 9 | 10 | ## 3. Specification Updates 11 | - [x] 3.1 Capture the non-interactive scenarios (`all`, `none`, list, invalid) in the change delta without modifying `specs/cli-init/spec.md` directly. 12 | - [x] 3.2 Document that CLI help reflects the available tool IDs managed by `AI_TOOLS`. 13 | 14 | ## 4. Testing 15 | - [x] 4.1 Add unit coverage for parsing `--tools` values, including invalid entries. 16 | - [x] 4.2 Add integration coverage ensuring non-interactive runs generate the expected files and exit codes. 17 | - [x] 4.3 Verify the interactive flow remains unchanged when `--tools` is omitted. 18 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-spec-commands/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks (Phase 3: Builds on add-zod-validation and add-change-commands) 2 | 3 | ## 1. Command Implementation 4 | - [x] 1.1 Create src/commands/spec.ts 5 | - [x] 1.2 Import RequirementSchema, ScenarioSchema, SpecSchema from src/core/schemas/ 6 | - [x] 1.3 Import markdown parser from src/core/parsers/markdown-parser.ts 7 | - [x] 1.4 Import SpecValidator from src/core/validation/validator.ts 8 | - [x] 1.5 Import JSON converter from src/core/converters/json-converter.ts 9 | - [x] 1.6 Implement show subcommand with JSON output using existing converter 10 | - [x] 1.7 Implement list subcommand 11 | - [x] 1.8 Implement validate subcommand using existing SpecValidator 12 | - [x] 1.9 Add filtering options (--requirements, --no-scenarios, -r) 13 | - [x] 1.10 Add --strict mode support (leveraging existing validation infrastructure) 14 | - [x] 1.11 Add --json flag for validation reports 15 | 16 | ## 2. Integration 17 | - [x] 2.1 Register spec command in src/cli/index.ts 18 | - [x] 2.2 Add integration tests for all subcommands 19 | - [x] 2.3 Test JSON output validation 20 | - [x] 2.4 Test filtering options 21 | - [x] 2.5 Test validation with strict mode 22 | - [x] 2.6 Update CLI help documentation (add 'spec' command to main help, document subcommands: show, list, validate) -------------------------------------------------------------------------------- /openspec/changes/archive/2025-12-20-add-global-config-dir/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Core Implementation 2 | 3 | - [x] 1.1 Create `src/core/global-config.ts` with path resolution 4 | - Implement `getGlobalConfigDir()` following XDG spec 5 | - Support `$XDG_CONFIG_HOME` environment variable override 6 | - Platform-specific fallbacks (Unix: `~/.config/`, Windows: `%APPDATA%`) 7 | - [x] 1.2 Define TypeScript interfaces for config shape 8 | - `GlobalConfig` interface with optional fields 9 | - Start minimal: just `featureFlags?: Record` 10 | - [x] 1.3 Implement config loading with defaults 11 | - `getGlobalConfig()` - reads config.json if exists, merges with defaults 12 | - No directory/file creation on read (lazy initialization) 13 | - [x] 1.4 Implement config saving 14 | - `saveGlobalConfig(config)` - writes config.json, creates directory if needed 15 | 16 | ## 2. Integration 17 | 18 | - [x] 2.1 Export new module from `src/core/index.ts` 19 | - [x] 2.2 Add constants for config file name and directory name 20 | 21 | ## 3. Testing 22 | 23 | - [x] 3.1 Manual testing of path resolution on current platform 24 | - [x] 3.2 Test with/without `$XDG_CONFIG_HOME` set 25 | - [x] 3.3 Test config load when file doesn't exist (should return defaults) 26 | - [x] 3.4 Unit tests in `test/core/global-config.test.ts` (18 tests) 27 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-01-11-add-update-command/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Update Command Implementation 4 | - [x] 1.1 Create `src/core/update.ts` with `UpdateCommand` class 5 | - [x] 1.2 Check if `openspec` directory exists (use `FileSystemUtils.directoryExists`) 6 | - [x] 1.3 Write `readmeTemplate` to `openspec/README.md` using `FileSystemUtils.writeFile` 7 | - [x] 1.4 Update `CLAUDE.md` using markers via `FileSystemUtils.updateFileWithMarkers` and `TemplateManager.getClaudeTemplate()` 8 | - [x] 1.5 Display ASCII-safe success message: `Updated OpenSpec instructions` 9 | 10 | ## 2. CLI Integration 11 | - [x] 2.1 Register `update` command in `src/cli/index.ts` 12 | - [x] 2.2 Add command description: `Update OpenSpec instruction files` 13 | - [x] 2.3 Handle errors with `ora().fail(...)` and exit code 1 (missing `openspec` directory, file write errors) 14 | 15 | ## 3. Testing 16 | - [x] 3.1 Verify `openspec/README.md` is fully replaced with latest template 17 | - [x] 3.2 Verify `CLAUDE.md` OpenSpec block updates without altering user content outside markers 18 | - [x] 3.3 Verify idempotency (running twice yields identical files, no duplicate markers) 19 | - [x] 3.4 Verify error when `openspec` directory is missing with friendly message 20 | - [x] 3.5 Verify success message displays properly in ASCII-only terminals -------------------------------------------------------------------------------- /src/core/configurators/slash/costrict.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS = { 5 | proposal: '.cospec/openspec/commands/openspec-proposal.md', 6 | apply: '.cospec/openspec/commands/openspec-apply.md', 7 | archive: '.cospec/openspec/commands/openspec-archive.md', 8 | } as const satisfies Record; 9 | 10 | const FRONTMATTER = { 11 | proposal: `--- 12 | description: "Scaffold a new OpenSpec change and validate strictly." 13 | argument-hint: feature description or request 14 | ---`, 15 | apply: `--- 16 | description: "Implement an approved OpenSpec change and keep tasks in sync." 17 | argument-hint: change-id 18 | ---`, 19 | archive: `--- 20 | description: "Archive a deployed OpenSpec change and update specs." 21 | argument-hint: change-id 22 | ---` 23 | } as const satisfies Record; 24 | 25 | export class CostrictSlashCommandConfigurator extends SlashCommandConfigurator { 26 | readonly toolId = 'costrict'; 27 | readonly isAvailable = true; 28 | 29 | protected getRelativePath(id: SlashCommandId): string { 30 | return FILE_PATHS[id]; 31 | } 32 | 33 | protected getFrontmatter(id: SlashCommandId): string | undefined { 34 | return FRONTMATTER[id]; 35 | } 36 | } -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-add-slash-command-support/specs/cli-update/spec.md: -------------------------------------------------------------------------------- 1 | ## ADDED Requirements 2 | ### Requirement: Slash Command Updates 3 | The update command SHALL refresh existing slash command files for configured tools without creating new ones. 4 | 5 | #### Scenario: Updating slash commands for Claude Code 6 | - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` 7 | - **THEN** refresh each file using shared templates 8 | - **AND** ensure templates include instructions for the relevant workflow stage 9 | 10 | #### Scenario: Updating slash commands for Cursor 11 | - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` 12 | - **THEN** refresh each file using shared templates 13 | - **AND** ensure templates include instructions for the relevant workflow stage 14 | 15 | #### Scenario: Updating slash commands for OpenCode 16 | - **WHEN** `.opencode/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` 17 | - **THEN** refresh each file using shared templates 18 | - **AND** ensure templates include instructions for the relevant workflow stage 19 | 20 | #### Scenario: Missing slash command file 21 | - **WHEN** a tool lacks a slash command file 22 | - **THEN** do not create a new file during update 23 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-update-agent-file-name/specs/openspec-conventions/spec.md: -------------------------------------------------------------------------------- 1 | ## MODIFIED Requirements 2 | 3 | ### Requirement: Project Structure 4 | An OpenSpec project SHALL maintain a consistent directory structure for specifications and changes. 5 | 6 | #### Scenario: Initializing project structure 7 | - **WHEN** an OpenSpec project is initialized 8 | - **THEN** it SHALL have this structure: 9 | ``` 10 | openspec/ 11 | ├── project.md # Project-specific context 12 | ├── AGENTS.md # AI assistant instructions 13 | ├── specs/ # Current deployed capabilities 14 | │ └── [capability]/ # Single, focused capability 15 | │ ├── spec.md # WHAT and WHY 16 | │ └── design.md # HOW (optional, for established patterns) 17 | └── changes/ # Proposed changes 18 | ├── [change-name]/ # Descriptive change identifier 19 | │ ├── proposal.md # Why, what, and impact 20 | │ ├── tasks.md # Implementation checklist 21 | │ ├── design.md # Technical decisions (optional) 22 | │ └── specs/ # Complete future state 23 | │ └── [capability]/ 24 | │ └── spec.md # Clean markdown (no diff syntax) 25 | └── archive/ # Completed changes 26 | └── YYYY-MM-DD-[name]/ 27 | ``` 28 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-add-windsurf-workflows/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. CLI wiring 2 | - [x] 1.1 Add Windsurf to the selectable AI tools in `openspec init`, including "already configured" detection. 3 | - [x] 1.2 Register a `WindsurfSlashCommandConfigurator` that writes workflows to `.windsurf/workflows/` and ensures the directory exists. 4 | - [x] 1.3 Ensure `openspec update` pulls the Windsurf configurator when winds is selected and skips creation when files are absent. 5 | 6 | ## 2. Workflow templates 7 | - [x] 2.1 Reuse the shared proposal/apply/archive bodies, adding Windsurf-specific headings/description before the OpenSpec markers. 8 | - [x] 2.2 Confirm generated Markdown (per file) stays comfortably under the 12k character ceiling noted in the Windsurf docs. 9 | 10 | ## 3. Tests & safeguards 11 | - [x] 3.1 Extend init tests to assert creation of `.windsurf/workflows/openspec-*.md` when Windsurf is chosen. 12 | - [x] 3.2 Extend update tests to assert existing Windsurf workflows are refreshed and non-existent files are ignored. 13 | - [x] 3.3 Add regression coverage for marker preservation inside Windsurf workflow files. 14 | 15 | ## 4. Documentation 16 | - [x] 4.1 Update README (and any user-facing docs) to list Windsurf under native slash/workflow integrations. 17 | - [x] 4.2 Call out Windsurf workflow support in release notes or CHANGELOG if applicable. 18 | -------------------------------------------------------------------------------- /src/core/configurators/slash/iflow.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.iflow/commands/openspec-proposal.md', 6 | apply: '.iflow/commands/openspec-apply.md', 7 | archive: '.iflow/commands/openspec-archive.md' 8 | }; 9 | 10 | const FRONTMATTER: Record = { 11 | proposal: `--- 12 | name: /openspec-proposal 13 | id: openspec-proposal 14 | category: OpenSpec 15 | description: Scaffold a new OpenSpec change and validate strictly. 16 | ---`, 17 | apply: `--- 18 | name: /openspec-apply 19 | id: openspec-apply 20 | category: OpenSpec 21 | description: Implement an approved OpenSpec change and keep tasks in sync. 22 | ---`, 23 | archive: `--- 24 | name: /openspec-archive 25 | id: openspec-archive 26 | category: OpenSpec 27 | description: Archive a deployed OpenSpec change and update specs. 28 | ---` 29 | }; 30 | 31 | export class IflowSlashCommandConfigurator extends SlashCommandConfigurator { 32 | readonly toolId = 'iflow'; 33 | readonly isAvailable = true; 34 | 35 | protected getRelativePath(id: SlashCommandId): string { 36 | return FILE_PATHS[id]; 37 | } 38 | 39 | protected getFrontmatter(id: SlashCommandId): string { 40 | return FRONTMATTER[id]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/utils/task-progress.ts: -------------------------------------------------------------------------------- 1 | import { promises as fs } from 'fs'; 2 | import path from 'path'; 3 | 4 | const TASK_PATTERN = /^[-*]\s+\[[\sx]\]/i; 5 | const COMPLETED_TASK_PATTERN = /^[-*]\s+\[x\]/i; 6 | 7 | export interface TaskProgress { 8 | total: number; 9 | completed: number; 10 | } 11 | 12 | export function countTasksFromContent(content: string): TaskProgress { 13 | const lines = content.split('\n'); 14 | let total = 0; 15 | let completed = 0; 16 | for (const line of lines) { 17 | if (line.match(TASK_PATTERN)) { 18 | total++; 19 | if (line.match(COMPLETED_TASK_PATTERN)) { 20 | completed++; 21 | } 22 | } 23 | } 24 | return { total, completed }; 25 | } 26 | 27 | export async function getTaskProgressForChange(changesDir: string, changeName: string): Promise { 28 | const tasksPath = path.join(changesDir, changeName, 'tasks.md'); 29 | try { 30 | const content = await fs.readFile(tasksPath, 'utf-8'); 31 | return countTasksFromContent(content); 32 | } catch { 33 | return { total: 0, completed: 0 }; 34 | } 35 | } 36 | 37 | export function formatTaskStatus(progress: TaskProgress): string { 38 | if (progress.total === 0) return 'No tasks'; 39 | if (progress.completed === progress.total) return '✓ Complete'; 40 | return `${progress.completed}/${progress.total} tasks`; 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/core/configurators/slash/crush.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.crush/commands/openspec/proposal.md', 6 | apply: '.crush/commands/openspec/apply.md', 7 | archive: '.crush/commands/openspec/archive.md' 8 | }; 9 | 10 | const FRONTMATTER: Record = { 11 | proposal: `--- 12 | name: OpenSpec: Proposal 13 | description: Scaffold a new OpenSpec change and validate strictly. 14 | category: OpenSpec 15 | tags: [openspec, change] 16 | ---`, 17 | apply: `--- 18 | name: OpenSpec: Apply 19 | description: Implement an approved OpenSpec change and keep tasks in sync. 20 | category: OpenSpec 21 | tags: [openspec, apply] 22 | ---`, 23 | archive: `--- 24 | name: OpenSpec: Archive 25 | description: Archive a deployed OpenSpec change and update specs. 26 | category: OpenSpec 27 | tags: [openspec, archive] 28 | ---` 29 | }; 30 | 31 | export class CrushSlashCommandConfigurator extends SlashCommandConfigurator { 32 | readonly toolId = 'crush'; 33 | readonly isAvailable = true; 34 | 35 | protected getRelativePath(id: SlashCommandId): string { 36 | return FILE_PATHS[id]; 37 | } 38 | 39 | protected getFrontmatter(id: SlashCommandId): string { 40 | return FRONTMATTER[id]; 41 | } 42 | } -------------------------------------------------------------------------------- /src/core/configurators/slash/cursor.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.cursor/commands/openspec-proposal.md', 6 | apply: '.cursor/commands/openspec-apply.md', 7 | archive: '.cursor/commands/openspec-archive.md' 8 | }; 9 | 10 | const FRONTMATTER: Record = { 11 | proposal: `--- 12 | name: /openspec-proposal 13 | id: openspec-proposal 14 | category: OpenSpec 15 | description: Scaffold a new OpenSpec change and validate strictly. 16 | ---`, 17 | apply: `--- 18 | name: /openspec-apply 19 | id: openspec-apply 20 | category: OpenSpec 21 | description: Implement an approved OpenSpec change and keep tasks in sync. 22 | ---`, 23 | archive: `--- 24 | name: /openspec-archive 25 | id: openspec-archive 26 | category: OpenSpec 27 | description: Archive a deployed OpenSpec change and update specs. 28 | ---` 29 | }; 30 | 31 | export class CursorSlashCommandConfigurator extends SlashCommandConfigurator { 32 | readonly toolId = 'cursor'; 33 | readonly isAvailable = true; 34 | 35 | protected getRelativePath(id: SlashCommandId): string { 36 | return FILE_PATHS[id]; 37 | } 38 | 39 | protected getFrontmatter(id: SlashCommandId): string { 40 | return FRONTMATTER[id]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/core/configurators/slash/claude.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.claude/commands/openspec/proposal.md', 6 | apply: '.claude/commands/openspec/apply.md', 7 | archive: '.claude/commands/openspec/archive.md' 8 | }; 9 | 10 | const FRONTMATTER: Record = { 11 | proposal: `--- 12 | name: OpenSpec: Proposal 13 | description: Scaffold a new OpenSpec change and validate strictly. 14 | category: OpenSpec 15 | tags: [openspec, change] 16 | ---`, 17 | apply: `--- 18 | name: OpenSpec: Apply 19 | description: Implement an approved OpenSpec change and keep tasks in sync. 20 | category: OpenSpec 21 | tags: [openspec, apply] 22 | ---`, 23 | archive: `--- 24 | name: OpenSpec: Archive 25 | description: Archive a deployed OpenSpec change and update specs. 26 | category: OpenSpec 27 | tags: [openspec, archive] 28 | ---` 29 | }; 30 | 31 | export class ClaudeSlashCommandConfigurator extends SlashCommandConfigurator { 32 | readonly toolId = 'claude'; 33 | readonly isAvailable = true; 34 | 35 | protected getRelativePath(id: SlashCommandId): string { 36 | return FILE_PATHS[id]; 37 | } 38 | 39 | protected getFrontmatter(id: SlashCommandId): string { 40 | return FRONTMATTER[id]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-01-11-add-update-command/proposal.md: -------------------------------------------------------------------------------- 1 | # Add Update Command 2 | 3 | ## Why 4 | 5 | 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. 6 | 7 | ## What Changes 8 | 9 | - Add new `openspec update` CLI command that updates OpenSpec instructions 10 | - Replace `openspec/README.md` with the latest template 11 | - Safe because this file is fully OpenSpec-managed 12 | - Update only the OpenSpec-managed block in `CLAUDE.md` using markers 13 | - Preserve all user content outside markers 14 | - If `CLAUDE.md` is missing, create it with the managed block 15 | - Display success message after update (ASCII-safe): "Updated OpenSpec instructions" 16 | - A leading checkmark MAY be shown when the terminal supports it 17 | - Operation is idempotent (re-running yields identical results) 18 | 19 | ## Impact 20 | 21 | - Affected specs: `cli-update` (new capability) 22 | - Affected code: 23 | - `src/core/update.ts` (new command class, mirrors `InitCommand` placement) 24 | - `src/cli/index.ts` (register new command) 25 | - Uses existing templates via `TemplateManager` and `readmeTemplate` 26 | 27 | ## Out of Scope 28 | 29 | - No `.openspec/config.json` is introduced by this change. The default directory name `openspec` is used. -------------------------------------------------------------------------------- /src/core/configurators/slash/codebuddy.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.codebuddy/commands/openspec/proposal.md', 6 | apply: '.codebuddy/commands/openspec/apply.md', 7 | archive: '.codebuddy/commands/openspec/archive.md' 8 | }; 9 | 10 | const FRONTMATTER: Record = { 11 | proposal: `--- 12 | name: OpenSpec: Proposal 13 | description: Scaffold a new OpenSpec change and validate strictly. 14 | category: OpenSpec 15 | tags: [openspec, change] 16 | ---`, 17 | apply: `--- 18 | name: OpenSpec: Apply 19 | description: Implement an approved OpenSpec change and keep tasks in sync. 20 | category: OpenSpec 21 | tags: [openspec, apply] 22 | ---`, 23 | archive: `--- 24 | name: OpenSpec: Archive 25 | description: Archive a deployed OpenSpec change and update specs. 26 | category: OpenSpec 27 | tags: [openspec, archive] 28 | ---` 29 | }; 30 | 31 | export class CodeBuddySlashCommandConfigurator extends SlashCommandConfigurator { 32 | readonly toolId = 'codebuddy'; 33 | readonly isAvailable = true; 34 | 35 | protected getRelativePath(id: SlashCommandId): string { 36 | return FILE_PATHS[id]; 37 | } 38 | 39 | protected getFrontmatter(id: SlashCommandId): string { 40 | return FRONTMATTER[id]; 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-update-release-automation/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. Release workflow automation 2 | - [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`. 3 | - [x] 1.2 Configure the action with `createGithubReleases: true` and document required secrets (`NPM_TOKEN`, default `GITHUB_TOKEN`) plus recommended concurrency safeguards. 4 | - [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. 5 | 6 | ## 2. Package release script 7 | - [x] 2.1 Add a `release` script to `package.json` that builds the project and runs `changeset publish` using pnpm. 8 | - [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. 9 | 10 | ## 3. Documentation and recovery steps 11 | - [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. 12 | - [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. 13 | -------------------------------------------------------------------------------- /src/core/configurators/slash/factory.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.factory/commands/openspec-proposal.md', 6 | apply: '.factory/commands/openspec-apply.md', 7 | archive: '.factory/commands/openspec-archive.md' 8 | }; 9 | 10 | const FRONTMATTER: Record = { 11 | proposal: `--- 12 | description: Scaffold a new OpenSpec change and validate strictly. 13 | argument-hint: request or feature description 14 | ---`, 15 | apply: `--- 16 | description: Implement an approved OpenSpec change and keep tasks in sync. 17 | argument-hint: change-id 18 | ---`, 19 | archive: `--- 20 | description: Archive a deployed OpenSpec change and update specs. 21 | argument-hint: change-id 22 | ---` 23 | }; 24 | 25 | export class FactorySlashCommandConfigurator extends SlashCommandConfigurator { 26 | readonly toolId = 'factory'; 27 | readonly isAvailable = true; 28 | 29 | protected getRelativePath(id: SlashCommandId): string { 30 | return FILE_PATHS[id]; 31 | } 32 | 33 | protected getFrontmatter(id: SlashCommandId): string { 34 | return FRONTMATTER[id]; 35 | } 36 | 37 | protected getBody(id: SlashCommandId): string { 38 | const baseBody = super.getBody(id); 39 | return `${baseBody}\n\n$ARGUMENTS`; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-22-add-archive-command-arguments/proposal.md: -------------------------------------------------------------------------------- 1 | # Add Archive Command Arguments 2 | 3 | ## Why 4 | 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 `. 5 | 6 | ## What Changes 7 | - Add `$ARGUMENTS` placeholder to the OpenCode archive slash command frontmatter (matching existing pattern for proposal command) 8 | - Update archive command template steps to validate the specific change ID argument when provided 9 | - Note: Codex, GitHub Copilot, and Amazon Q already have `$ARGUMENTS` for archive; Claude/Cursor/Windsurf/Kilocode don't support arguments 10 | 11 | ## Impact 12 | - Affected specs: `cli-update` (slash command generation logic) 13 | - Affected code: 14 | - `src/core/configurators/slash/opencode.ts` (add `$ARGUMENTS` to archive frontmatter) 15 | - `src/core/templates/slash-command-templates.ts` (archive template steps for argument validation) 16 | - Breaking: No - this is additive functionality that makes the command safer 17 | - User-facing: Yes - OpenCode users will be able to pass the change ID as an argument: `/openspec:archive ` 18 | -------------------------------------------------------------------------------- /openspec/changes/add-config-command/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 3 | Users need a way to view and modify their global OpenSpec settings without manually editing JSON files. The `add-global-config-dir` change 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. 4 | 5 | ## What Changes 6 | 7 | Add `openspec config` subcommand with the following operations: 8 | 9 | ```bash 10 | openspec config path # Show config file location 11 | openspec config list # Show all current settings 12 | openspec config get # Get a specific value 13 | openspec config set # Set a value 14 | openspec config reset [key] # Reset to defaults (all or specific key) 15 | ``` 16 | 17 | **Example usage:** 18 | ```bash 19 | $ openspec config path 20 | /Users/me/.config/openspec/config.json 21 | 22 | $ openspec config list 23 | enableTelemetry: true 24 | featureFlags: {} 25 | 26 | $ openspec config set enableTelemetry false 27 | Set enableTelemetry = false 28 | 29 | $ openspec config get enableTelemetry 30 | false 31 | ``` 32 | 33 | ## Impact 34 | 35 | - Affected specs: New `cli-config` capability 36 | - Affected code: 37 | - New `src/commands/config.ts` 38 | - Update CLI entry point to register config command 39 | - Dependencies: Requires `add-global-config-dir` to be implemented first 40 | -------------------------------------------------------------------------------- /.github/workflows/release-prepare.yml: -------------------------------------------------------------------------------- 1 | name: Release (prepare) 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | permissions: 8 | contents: write 9 | pull-requests: write 10 | 11 | concurrency: 12 | group: release-${{ github.ref }} 13 | cancel-in-progress: false 14 | 15 | jobs: 16 | prepare: 17 | if: github.repository == 'Fission-AI/OpenSpec' 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | 24 | - uses: pnpm/action-setup@v4 25 | with: 26 | version: 9 27 | 28 | - uses: actions/setup-node@v4 29 | with: 30 | node-version: '20' 31 | cache: 'pnpm' 32 | registry-url: 'https://registry.npmjs.org' 33 | scope: '@fission-ai' 34 | always-auth: true 35 | 36 | - run: pnpm install --frozen-lockfile 37 | 38 | # Opens/updates the Version Packages PR; publishes when the Version PR merges 39 | - name: Create/Update Version PR 40 | uses: changesets/action@v1 41 | with: 42 | title: 'chore(release): version packages' 43 | createGithubReleases: true 44 | # Use CI-specific release script: relies on version PR having been merged 45 | # so package.json already contains the bumped version. 46 | publish: pnpm run release:ci 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 50 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 51 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-remove-diff-command/tasks.md: -------------------------------------------------------------------------------- 1 | # Remove Diff Command - Tasks 2 | 3 | ## 1. Remove Core Implementation 4 | - [x] Delete `/src/core/diff.ts` 5 | - [x] Remove DiffCommand import from `/src/cli/index.ts` 6 | - [x] Remove diff command registration from CLI 7 | 8 | ## 2. Remove Specifications 9 | - [x] Delete `/openspec/specs/cli-diff/spec.md` 10 | - [x] Archive the spec for historical reference if needed 11 | 12 | ## 3. Update Dependencies 13 | - [x] Remove jest-diff from package.json dependencies 14 | - [x] Run pnpm install to update lock file 15 | 16 | ## 4. Update Documentation 17 | - [x] Update main README.md to remove diff command references 18 | - [x] Update openspec/README.md to remove diff command from command list 19 | - [x] Update CLAUDE.md template if it mentions diff command 20 | - [x] Update any example workflows that use diff command 21 | 22 | ## 5. Update Related Files 23 | - [x] Search and update any remaining references to "openspec diff" in: 24 | - Template files 25 | - Test files (if any exist for diff command) 26 | - Archive documentation 27 | - Change proposals 28 | 29 | ## 7. Testing 30 | - [x] Ensure all tests pass after removal 31 | - [x] Verify CLI help text no longer shows diff command 32 | - [x] Test that show command provides adequate replacement functionality 33 | 34 | ## 8. Documentation of Alternative Workflows 35 | - [x] Document how to use `openspec show` for viewing changes 36 | - [x] Document how to use git diff for file comparisons 37 | - [x] Add migration guide to help text or documentation -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-06-add-init-command/proposal.md: -------------------------------------------------------------------------------- 1 | # Add Init Command for OpenSpec 2 | 3 | ## Why 4 | 5 | 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. 6 | 7 | ## What Changes 8 | 9 | - Add `openspec init` CLI command that creates the complete OpenSpec directory structure 10 | - Generate template files (README.md with AI instructions, project.md template) 11 | - Interactive prompt to select which AI tools to configure (Claude Code initially, others marked as "coming soon") 12 | - Support for multiple AI coding assistants with extensible plugin architecture 13 | - Smart file updates using content markers to preserve existing configurations 14 | - Custom directory naming with `--dir` flag 15 | - Validation to prevent overwriting existing OpenSpec structures 16 | - Clear error messages with helpful guidance (e.g., suggesting 'openspec update' for existing structures) 17 | - Display actionable next steps after successful initialization 18 | 19 | ### Breaking Changes 20 | - None - this is a new feature 21 | 22 | ## Impact 23 | 24 | - Affected specs: None (new feature) 25 | - Affected code: 26 | - src/cli/index.ts (add init command) 27 | - src/core/init.ts (new - initialization logic) 28 | - src/core/templates/ (new - template files) 29 | - src/core/configurators/ (new - AI tool plugins) 30 | - src/utils/file-system.ts (new - file operations) -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-sort-active-changes-by-progress/proposal.md: -------------------------------------------------------------------------------- 1 | # Change: Sort Active Changes by Progress 2 | 3 | ## Problem 4 | - The dashboard currently lists active changes in filesystem discovery order. 5 | - Users cannot quickly spot proposals that have not started or are nearly complete. 6 | - Inconsistent ordering between runs makes it harder to track progress when many changes exist. 7 | 8 | ## Proposal 9 | 1. Update the Active Changes list in the dashboard to sort by percentage of completion in ascending order so 0% items show first. 10 | 2. When two changes share the same completion percentage, break ties deterministically by change identifier (alphabetical). 11 | 12 | ## Benefits 13 | - Highlights work that has not started yet, enabling quicker prioritization. 14 | - Provides consistent ordering across machines and repeated runs. 15 | - Keeps the dashboard compact while communicating the most important status signal. 16 | 17 | ## Risks & Mitigations 18 | - **Risk:** Sorting logic could regress rendering when progress data is missing. 19 | - **Mitigation:** Treat missing progress as 0% so items still surface and document behavior in tests. 20 | - **Risk:** Additional sorting could impact performance for large change sets. 21 | - **Mitigation:** The number of active changes is typically small; sorting a few entries is negligible. 22 | 23 | ## Success Criteria 24 | - Dashboard output shows active changes ordered by ascending completion percentage with deterministic tie-breaking. 25 | - Unit coverage verifying the sort when percentages vary and when ties occur. 26 | -------------------------------------------------------------------------------- /src/core/templates/index.ts: -------------------------------------------------------------------------------- 1 | import { agentsTemplate } from './agents-template.js'; 2 | import { projectTemplate, ProjectContext } from './project-template.js'; 3 | import { claudeTemplate } from './claude-template.js'; 4 | import { clineTemplate } from './cline-template.js'; 5 | import { costrictTemplate } from './costrict-template.js'; 6 | import { agentsRootStubTemplate } from './agents-root-stub.js'; 7 | import { getSlashCommandBody, SlashCommandId } from './slash-command-templates.js'; 8 | 9 | export interface Template { 10 | path: string; 11 | content: string | ((context: ProjectContext) => string); 12 | } 13 | 14 | export class TemplateManager { 15 | static getTemplates(context: ProjectContext = {}): Template[] { 16 | return [ 17 | { 18 | path: 'AGENTS.md', 19 | content: agentsTemplate 20 | }, 21 | { 22 | path: 'project.md', 23 | content: projectTemplate(context) 24 | } 25 | ]; 26 | } 27 | 28 | static getClaudeTemplate(): string { 29 | return claudeTemplate; 30 | } 31 | 32 | static getClineTemplate(): string { 33 | return clineTemplate; 34 | } 35 | 36 | static getCostrictTemplate(): string { 37 | return costrictTemplate; 38 | } 39 | 40 | static getAgentsStandardTemplate(): string { 41 | return agentsRootStubTemplate; 42 | } 43 | 44 | static getSlashCommandBody(id: SlashCommandId): string { 45 | return getSlashCommandBody(id); 46 | } 47 | } 48 | 49 | export { ProjectContext } from './project-template.js'; 50 | export type { SlashCommandId } from './slash-command-templates.js'; 51 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-add-slash-command-support/specs/cli-init/spec.md: -------------------------------------------------------------------------------- 1 | ## ADDED Requirements 2 | ### Requirement: Slash Command Configuration 3 | The init command SHALL generate slash command files for supported editors using shared templates. 4 | 5 | #### Scenario: Generating slash commands for Claude Code 6 | - **WHEN** the user selects Claude Code during initialization 7 | - **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md` 8 | - **AND** populate each file from shared templates so command text matches other tools 9 | - **AND** each template includes instructions for the relevant OpenSpec workflow stage 10 | 11 | #### Scenario: Generating slash commands for Cursor 12 | - **WHEN** the user selects Cursor during initialization 13 | - **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md` 14 | - **AND** populate each file from shared templates so command text matches other tools 15 | - **AND** each template includes instructions for the relevant OpenSpec workflow stage 16 | 17 | #### Scenario: Generating slash commands for OpenCode 18 | - **WHEN** the user selects OpenCode during initialization 19 | - **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md` 20 | - **AND** populate each file from shared templates so command text matches other tools 21 | - **AND** each template includes instructions for the relevant OpenSpec workflow stage 22 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-spec-commands/specs/cli-spec/spec.md: -------------------------------------------------------------------------------- 1 | ## ADDED Requirements 2 | 3 | ### Requirement: Spec Command 4 | 5 | The system SHALL provide a `spec` command with subcommands for displaying, listing, and validating specifications. 6 | 7 | #### Scenario: Show spec as JSON 8 | 9 | - **WHEN** executing `openspec spec show init --json` 10 | - **THEN** parse the markdown spec file 11 | - **AND** extract headings and content hierarchically 12 | - **AND** output valid JSON to stdout 13 | 14 | #### Scenario: List all specs 15 | 16 | - **WHEN** executing `openspec spec list` 17 | - **THEN** scan the openspec/specs directory 18 | - **AND** return list of all available capabilities 19 | - **AND** support JSON output with `--json` flag 20 | 21 | #### Scenario: Filter spec content 22 | 23 | - **WHEN** executing `openspec spec show init --requirements` 24 | - **THEN** display only requirement names and SHALL statements 25 | - **AND** exclude scenario content 26 | 27 | #### Scenario: Validate spec structure 28 | 29 | - **WHEN** executing `openspec spec validate init` 30 | - **THEN** parse the spec file 31 | - **AND** validate against Zod schema 32 | - **AND** report any structural issues 33 | 34 | ### Requirement: JSON Schema Definition 35 | 36 | The system SHALL define Zod schemas that accurately represent the spec structure for runtime validation. 37 | 38 | #### Scenario: Schema validation 39 | 40 | - **WHEN** parsing a spec into JSON 41 | - **THEN** validate the structure using Zod schemas 42 | - **AND** ensure all required fields are present 43 | - **AND** provide clear error messages for validation failures -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-improve-validate-error-messages/proposal.md: -------------------------------------------------------------------------------- 1 | # improve-validate-error-messages 2 | 3 | ## Why 4 | 5 | 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. 6 | 7 | ## What Changes 8 | 9 | - Validation errors SHALL include specific remediation steps (what to change and where). 10 | - "No deltas found" error SHALL guide users to create `specs/` with proper delta headers and suggest debug commands. 11 | - Missing required sections (Spec: Purpose/Requirements; Change: Why/What Changes) SHALL include expected header names and a minimal skeleton example. 12 | - Likely misformatted scenarios (bulleted WHEN/THEN/AND) SHALL emit a targeted warning explaining the `#### Scenario:` format and show a conversion template. 13 | - All reported issues SHALL include the source file path and structured location (e.g., `deltas[0].requirements[0]`). 14 | - Non-JSON output SHOULD end with a short "Next steps" footer when invalid. 15 | 16 | ## Impact 17 | 18 | - Affected CLI: validate 19 | - Affected code: 20 | - `src/commands/validate.ts` 21 | - `src/core/validation/validator.ts` 22 | - `src/core/validation/constants.ts` 23 | - `src/core/parsers/*` (wrapping thrown errors with richer context) 24 | 25 | 26 | -------------------------------------------------------------------------------- /openspec/changes/make-validation-scope-aware/specs/cli-validate/spec.md: -------------------------------------------------------------------------------- 1 | ## ADDED Requirements 2 | ### Requirement: Scope-Aware Change Validation 3 | The validator SHALL validate only artifacts that exist for a change, avoiding errors for proposal-only or tooling-only changes. 4 | 5 | #### Scenario: Proposal-only change 6 | - **WHEN** a change contains `proposal.md` but has no `specs/` directory or contains no `*/spec.md` files 7 | - **THEN** validate the proposal (Why/What sections) 8 | - **AND** do not require or validate spec deltas 9 | 10 | #### Scenario: Delta validation when specs exist 11 | - **WHEN** a change contains one or more `specs//spec.md` files 12 | - **THEN** validate delta-formatted specs with existing rules (SHALL/MUST, scenarios, duplicates, conflicts) 13 | 14 | ## MODIFIED Requirements 15 | ### Requirement: Validation SHALL provide actionable remediation steps 16 | Validation output SHALL include specific guidance to fix each error, including expected structure, example headers, and suggested commands to verify fixes. 17 | 18 | #### Scenario: No deltas found in change 19 | - **WHEN** validating a change that contains `specs/` with one or more `*/spec.md` files but the parser finds zero deltas 20 | - **THEN** show error "No deltas found" with guidance: 21 | - Ensure `openspec/changes/{id}/specs/` has `.md` files that include delta headers 22 | - Use delta headers: `## ADDED Requirements`, `## MODIFIED Requirements`, `## REMOVED Requirements`, `## RENAMED Requirements` 23 | - Each requirement must include at least one `#### Scenario:` block 24 | - Try: `openspec change show {id} --json --deltas-only` to inspect parsed deltas 25 | 26 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-add-kilocode-workflows/specs/cli-update/spec.md: -------------------------------------------------------------------------------- 1 | ## MODIFIED Requirements 2 | ### Requirement: Slash Command Updates 3 | The update command SHALL refresh existing slash command files for configured tools without creating new ones. 4 | 5 | #### Scenario: Updating slash commands for Claude Code 6 | - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` 7 | - **THEN** refresh each file using shared templates 8 | - **AND** ensure templates include instructions for the relevant workflow stage 9 | 10 | #### Scenario: Updating slash commands for Cursor 11 | - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` 12 | - **THEN** refresh each file using shared templates 13 | - **AND** ensure templates include instructions for the relevant workflow stage 14 | 15 | #### Scenario: Updating slash commands for OpenCode 16 | - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` 17 | - **THEN** refresh each file using shared templates 18 | - **AND** ensure templates include instructions for the relevant workflow stage 19 | 20 | #### Scenario: Updating slash commands for Kilo Code 21 | - **WHEN** `.kilocode/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` 22 | - **THEN** refresh each file using shared templates wrapped in OpenSpec markers 23 | - **AND** ensure templates include instructions for the relevant workflow stage 24 | 25 | #### Scenario: Missing slash command file 26 | - **WHEN** a tool lacks a slash command file 27 | - **THEN** do not create a new file during update 28 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-add-windsurf-workflows/specs/cli-update/spec.md: -------------------------------------------------------------------------------- 1 | ## MODIFIED Requirements 2 | ### Requirement: Slash Command Updates 3 | The update command SHALL refresh existing slash command files for configured tools without creating new ones. 4 | 5 | #### Scenario: Updating slash commands for Claude Code 6 | - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` 7 | - **THEN** refresh each file using shared templates 8 | - **AND** ensure templates include instructions for the relevant workflow stage 9 | 10 | #### Scenario: Updating slash commands for Cursor 11 | - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` 12 | - **THEN** refresh each file using shared templates 13 | - **AND** ensure templates include instructions for the relevant workflow stage 14 | 15 | #### Scenario: Updating slash commands for OpenCode 16 | - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` 17 | - **THEN** refresh each file using shared templates 18 | - **AND** ensure templates include instructions for the relevant workflow stage 19 | 20 | #### Scenario: Updating slash commands for Windsurf 21 | - **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` 22 | - **THEN** refresh each file using shared templates wrapped in OpenSpec markers 23 | - **AND** ensure templates include instructions for the relevant workflow stage 24 | 25 | #### Scenario: Missing slash command file 26 | - **WHEN** a tool lacks a slash command file 27 | - **THEN** do not create a new file during update 28 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-12-add-view-dashboard-command/proposal.md: -------------------------------------------------------------------------------- 1 | # Change: Add View Dashboard Command 2 | 3 | ## Why 4 | 5 | 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. 6 | 7 | ## What Changes 8 | 9 | ### Added `openspec view` Command 10 | 11 | The new command provides an interactive dashboard displaying: 12 | - Summary metrics (total specs, requirements, changes, task progress) 13 | - Active changes with visual progress bars 14 | - Completed changes 15 | - Specifications with requirement counts 16 | 17 | ### Specifications Affected 18 | 19 | - **cli-view** (NEW): Complete specification for the view dashboard command 20 | 21 | ## Implementation Details 22 | 23 | ### File Structure 24 | - Created `/src/core/view.ts` implementing the `ViewCommand` class 25 | - Registered command in `/src/cli/index.ts` 26 | - Reuses existing utilities from `task-progress.ts` and `MarkdownParser` 27 | 28 | ### Visual Design 29 | - Uses Unicode box drawing characters for borders 30 | - Color coding: cyan for specs, yellow for active, green for completed 31 | - Progress bars using filled (█) and empty (░) blocks 32 | - Clean alignment with proper padding 33 | 34 | ### Technical Approach 35 | - Async data fetching from changes and specs directories 36 | - Parallel processing of specs and changes 37 | - Error handling for missing or invalid data 38 | - Maintains consistency with existing list command output -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-update-agent-file-name/specs/cli-init/spec.md: -------------------------------------------------------------------------------- 1 | ## MODIFIED Requirements 2 | 3 | ### Requirement: Directory Creation 4 | The command SHALL create the complete OpenSpec directory structure with all required directories and files. 5 | 6 | #### Scenario: Creating OpenSpec structure 7 | - **WHEN** `openspec init` is executed 8 | - **THEN** create the following directory structure: 9 | ``` 10 | openspec/ 11 | ├── project.md 12 | ├── AGENTS.md 13 | ├── specs/ 14 | └── changes/ 15 | └── archive/ 16 | ``` 17 | 18 | ### Requirement: File Generation 19 | The command SHALL generate required template files with appropriate content for immediate use. 20 | 21 | #### Scenario: Generating template files 22 | - **WHEN** initializing OpenSpec 23 | - **THEN** generate `AGENTS.md` containing complete OpenSpec instructions for AI assistants 24 | - **AND** generate `project.md` with project context template 25 | 26 | ### Requirement: AI Tool Configuration Details 27 | 28 | The command SHALL properly configure selected AI tools with OpenSpec-specific instructions using a marker system. 29 | 30 | #### Scenario: Creating new CLAUDE.md 31 | - **WHEN** CLAUDE.md does not exist 32 | - **THEN** create new file with OpenSpec content wrapped in markers including reference to `@openspec/AGENTS.md` 33 | 34 | ### Requirement: Success Output 35 | 36 | The command SHALL provide clear, actionable next steps upon successful initialization. 37 | 38 | #### Scenario: Displaying success message 39 | - **WHEN** initialization completes successfully 40 | - **THEN** include prompt: "Please explain the OpenSpec workflow from openspec/AGENTS.md and how I should work with you on this project" 41 | -------------------------------------------------------------------------------- /test/commands/spec.interactive-show.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, beforeEach, afterEach } from 'vitest'; 2 | import { promises as fs } from 'fs'; 3 | import path from 'path'; 4 | import { execSync } from 'child_process'; 5 | 6 | describe('spec show (interactive behavior)', () => { 7 | const projectRoot = process.cwd(); 8 | const testDir = path.join(projectRoot, 'test-spec-show-tmp'); 9 | const specsDir = path.join(testDir, 'openspec', 'specs'); 10 | const bin = path.join(projectRoot, 'bin', 'openspec.js'); 11 | 12 | 13 | beforeEach(async () => { 14 | await fs.mkdir(specsDir, { recursive: true }); 15 | const content = `## Purpose\nX\n\n## Requirements\n\n### Requirement: R\nText`; 16 | await fs.mkdir(path.join(specsDir, 's1'), { recursive: true }); 17 | await fs.writeFile(path.join(specsDir, 's1', 'spec.md'), content, 'utf-8'); 18 | }); 19 | 20 | afterEach(async () => { 21 | await fs.rm(testDir, { recursive: true, force: true }); 22 | }); 23 | 24 | it('errors when no arg and non-interactive', () => { 25 | const originalCwd = process.cwd(); 26 | const originalEnv = { ...process.env }; 27 | try { 28 | process.chdir(testDir); 29 | process.env.OPEN_SPEC_INTERACTIVE = '0'; 30 | let err: any; 31 | try { 32 | execSync(`node ${bin} spec show`, { encoding: 'utf-8' }); 33 | } catch (e) { err = e; } 34 | expect(err).toBeDefined(); 35 | expect(err.status).not.toBe(0); 36 | expect(err.stderr.toString()).toContain('Missing required argument '); 37 | } finally { 38 | process.chdir(originalCwd); 39 | process.env = originalEnv; 40 | } 41 | }); 42 | }); 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/core/configurators/slash/amazon-q.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandConfigurator } from './base.js'; 2 | import { SlashCommandId } from '../../templates/index.js'; 3 | 4 | const FILE_PATHS: Record = { 5 | proposal: '.amazonq/prompts/openspec-proposal.md', 6 | apply: '.amazonq/prompts/openspec-apply.md', 7 | archive: '.amazonq/prompts/openspec-archive.md' 8 | }; 9 | 10 | const FRONTMATTER: Record = { 11 | proposal: `--- 12 | description: Scaffold a new OpenSpec change and validate strictly. 13 | --- 14 | 15 | The user has requested the following change proposal. Use the openspec instructions to create their change proposal. 16 | 17 | 18 | $ARGUMENTS 19 | `, 20 | apply: `--- 21 | description: Implement an approved OpenSpec change and keep tasks in sync. 22 | --- 23 | 24 | The user wants to apply the following change. Use the openspec instructions to implement the approved change. 25 | 26 | 27 | $ARGUMENTS 28 | `, 29 | archive: `--- 30 | description: Archive a deployed OpenSpec change and update specs. 31 | --- 32 | 33 | The user wants to archive the following deployed change. Use the openspec instructions to archive the change and update specs. 34 | 35 | 36 | $ARGUMENTS 37 | ` 38 | }; 39 | 40 | export class AmazonQSlashCommandConfigurator extends SlashCommandConfigurator { 41 | readonly toolId = 'amazon-q'; 42 | readonly isAvailable = true; 43 | 44 | protected getRelativePath(id: SlashCommandId): string { 45 | return FILE_PATHS[id]; 46 | } 47 | 48 | protected getFrontmatter(id: SlashCommandId): string { 49 | return FRONTMATTER[id]; 50 | } 51 | } -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-adopt-delta-based-changes/specs/cli-archive/spec.md: -------------------------------------------------------------------------------- 1 | # CLI Archive Command - Changes 2 | 3 | ## MODIFIED Requirements 4 | 5 | ### Requirement: Spec Update Process 6 | 7 | Before moving the change to archive, the command SHALL apply delta changes to main specs to reflect the deployed reality. 8 | 9 | #### Scenario: Applying delta changes 10 | 11 | - **WHEN** archiving a change with delta-based specs 12 | - **THEN** parse and apply delta changes as defined in openspec-conventions 13 | - **AND** validate all operations before applying 14 | 15 | #### Scenario: Validating delta changes 16 | 17 | - **WHEN** processing delta changes 18 | - **THEN** perform validations as specified in openspec-conventions 19 | - **AND** if validation fails, show specific errors and abort 20 | 21 | #### Scenario: Conflict detection 22 | 23 | - **WHEN** applying deltas would create duplicate requirement headers 24 | - **THEN** abort with error message showing the conflict 25 | - **AND** suggest manual resolution 26 | 27 | ## ADDED Requirements 28 | 29 | ### Requirement: Display Output 30 | 31 | The command SHALL provide clear feedback about delta operations. 32 | 33 | #### Scenario: Showing delta application 34 | 35 | - **WHEN** applying delta changes 36 | - **THEN** display for each spec: 37 | - Number of requirements added 38 | - Number of requirements modified 39 | - Number of requirements removed 40 | - Number of requirements renamed 41 | - **AND** use standard output symbols (+ ~ - →) as defined in openspec-conventions: 42 | ``` 43 | Applying changes to specs/user-auth/spec.md: 44 | + 2 added 45 | ~ 3 modified 46 | - 1 removed 47 | → 1 renamed 48 | ``` -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-06-adopt-future-state-storage/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Update Core Documentation 4 | - [x] 1.1 Update openspec/README.md section on "Creating a Change Proposal" 5 | - [x] Replace `patches/` with `specs/` in directory structure 6 | - [x] Update step 3 to show storing complete future state 7 | - [x] Remove diff syntax instructions (+/- prefixes) 8 | 9 | ## 2. Migrate Existing Change 10 | - [x] 2.1 Convert add-init-command change to new format 11 | - [x] Create `specs/cli-init/spec.md` with clean content (no diff markers) 12 | - [x] Delete old `patches/` directory 13 | - [x] 2.2 Test that the migrated change is clear and reviewable 14 | 15 | ## 3. Update Documentation Examples 16 | - [x] 3.1 Update docs/PRD.md 17 | - [x] Fix directory structure examples (lines 376-382) 18 | - [x] Update archive examples (lines 778-783) 19 | - [x] Ensure consistency throughout 20 | - [x] 3.2 Update docs/openspec-walkthrough.md 21 | - [x] Replace diff examples with future state examples 22 | - [x] Ensure the walkthrough reflects new approach 23 | 24 | ## 4. Create New Spec 25 | - [x] 4.1 Finalize openspec-conventions spec in main specs/ directory 26 | - [x] Document the future state storage approach 27 | - [x] Include examples of good proposals 28 | - [x] Make it the source of truth for conventions 29 | 30 | ## 5. Validation 31 | - [x] 5.1 Verify all documentation is consistent 32 | - [x] 5.2 Test creating a new change with the new approach 33 | - [x] 5.3 Ensure GitHub PR view shows diffs clearly 34 | 35 | ## 6. Deployment 36 | - [x] 6.1 Get approval for this change 37 | - [x] 6.2 Implement all tasks above 38 | - [x] 6.3 After deployment, archive this change with completion date -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. CLI Behavior and Help 4 | - [x] 1.1 Un-deprecate top-level `openspec list`; mark `change list` as deprecated with warning that points to `openspec list` 5 | - [x] 1.2 Add support to list specs via `openspec list --specs` and keep `--changes` as default 6 | - [x] 1.3 Update command descriptions and `--help` output to emphasize verb–noun pattern 7 | - [x] 1.4 Keep `openspec spec ...` and `openspec change ...` commands working but print deprecation notices 8 | 9 | ## 2. Core List Logic 10 | - [x] 2.1 Extend `src/core/list.ts` to accept a mode: `changes` (default) or `specs` 11 | - [x] 2.2 Implement `specs` listing: scan `openspec/specs/*/spec.md`, compute requirement count via parser, format output consistently 12 | - [x] 2.3 Share output structure for both modes; preserve current text table; ensure JSON parity in future change 13 | 14 | ## 3. Specs and Conventions 15 | - [x] 3.1 Update `openspec/specs/cli-list/spec.md` to document `--specs` (and default to changes) 16 | - [x] 3.2 Update `openspec/specs/openspec-conventions/spec.md` with a requirement for verb–noun CLI design and deprecation guidance 17 | 18 | ## 4. Tests and Docs 19 | - [x] 4.1 Update tests: ensure `openspec list` works for changes and specs; keep `change list` tests but assert warning 20 | - [ ] 4.2 Update README and any usage docs to show new primary commands 21 | - [ ] 4.3 Add migration notes in repo CHANGELOG or README 22 | 23 | ## 5. Follow-ups (Optional, not in this change) 24 | - [ ] 5.1 Consider `openspec show --specs/--changes` for discovery without ids 25 | - [ ] 5.2 Consider JSON output for `openspec list` with `--json` for both modes 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/commands/spec.interactive-validate.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, beforeEach, afterEach } from 'vitest'; 2 | import { promises as fs } from 'fs'; 3 | import path from 'path'; 4 | import { execSync } from 'child_process'; 5 | 6 | describe('spec validate (interactive behavior)', () => { 7 | const projectRoot = process.cwd(); 8 | const testDir = path.join(projectRoot, 'test-spec-validate-tmp'); 9 | const specsDir = path.join(testDir, 'openspec', 'specs'); 10 | const bin = path.join(projectRoot, 'bin', 'openspec.js'); 11 | 12 | 13 | beforeEach(async () => { 14 | await fs.mkdir(specsDir, { recursive: true }); 15 | const content = `## Purpose\nValid spec for interactive test.\n\n## Requirements\n\n### Requirement: X\nText`; 16 | await fs.mkdir(path.join(specsDir, 's1'), { recursive: true }); 17 | await fs.writeFile(path.join(specsDir, 's1', 'spec.md'), content, 'utf-8'); 18 | }); 19 | 20 | afterEach(async () => { 21 | await fs.rm(testDir, { recursive: true, force: true }); 22 | }); 23 | 24 | it('errors when no arg and non-interactive', () => { 25 | const originalCwd = process.cwd(); 26 | const originalEnv = { ...process.env }; 27 | try { 28 | process.chdir(testDir); 29 | process.env.OPEN_SPEC_INTERACTIVE = '0'; 30 | let err: any; 31 | try { 32 | execSync(`node ${bin} spec validate`, { encoding: 'utf-8' }); 33 | } catch (e) { err = e; } 34 | expect(err).toBeDefined(); 35 | expect(err.status).not.toBe(0); 36 | expect(err.stderr.toString()).toContain('Missing required argument '); 37 | } finally { 38 | process.chdir(originalCwd); 39 | process.env = originalEnv; 40 | } 41 | }); 42 | }); 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/core/schemas/change.schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | import { RequirementSchema } from './base.schema.js'; 3 | import { 4 | MIN_WHY_SECTION_LENGTH, 5 | MAX_WHY_SECTION_LENGTH, 6 | MAX_DELTAS_PER_CHANGE, 7 | VALIDATION_MESSAGES 8 | } from '../validation/constants.js'; 9 | 10 | export const DeltaOperationType = z.enum(['ADDED', 'MODIFIED', 'REMOVED', 'RENAMED']); 11 | 12 | export const DeltaSchema = z.object({ 13 | spec: z.string().min(1, VALIDATION_MESSAGES.DELTA_SPEC_EMPTY), 14 | operation: DeltaOperationType, 15 | description: z.string().min(1, VALIDATION_MESSAGES.DELTA_DESCRIPTION_EMPTY), 16 | requirement: RequirementSchema.optional(), 17 | requirements: z.array(RequirementSchema).optional(), 18 | rename: z.object({ 19 | from: z.string(), 20 | to: z.string(), 21 | }).optional(), 22 | }); 23 | 24 | export const ChangeSchema = z.object({ 25 | name: z.string().min(1, VALIDATION_MESSAGES.CHANGE_NAME_EMPTY), 26 | why: z.string() 27 | .min(MIN_WHY_SECTION_LENGTH, VALIDATION_MESSAGES.CHANGE_WHY_TOO_SHORT) 28 | .max(MAX_WHY_SECTION_LENGTH, VALIDATION_MESSAGES.CHANGE_WHY_TOO_LONG), 29 | whatChanges: z.string().min(1, VALIDATION_MESSAGES.CHANGE_WHAT_EMPTY), 30 | deltas: z.array(DeltaSchema) 31 | .min(1, VALIDATION_MESSAGES.CHANGE_NO_DELTAS) 32 | .max(MAX_DELTAS_PER_CHANGE, VALIDATION_MESSAGES.CHANGE_TOO_MANY_DELTAS), 33 | metadata: z.object({ 34 | version: z.string().default('1.0.0'), 35 | format: z.literal('openspec-change'), 36 | sourcePath: z.string().optional(), 37 | }).optional(), 38 | }); 39 | 40 | export type DeltaOperation = z.infer; 41 | export type Delta = z.infer; 42 | export type Change = z.infer; -------------------------------------------------------------------------------- /scripts/test-postinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Test script for postinstall.js 4 | # Tests different scenarios: normal install, CI, opt-out 5 | 6 | set -e 7 | 8 | echo "======================================" 9 | echo "Testing OpenSpec Postinstall Script" 10 | echo "======================================" 11 | echo "" 12 | 13 | # Save original environment 14 | ORIGINAL_CI="${CI:-}" 15 | ORIGINAL_OPENSPEC_NO_COMPLETIONS="${OPENSPEC_NO_COMPLETIONS:-}" 16 | 17 | # Test 1: Normal install 18 | echo "Test 1: Normal install (should attempt to install completions)" 19 | echo "--------------------------------------" 20 | unset CI 21 | unset OPENSPEC_NO_COMPLETIONS 22 | node scripts/postinstall.js 23 | echo "" 24 | 25 | # Test 2: CI environment (should skip silently) 26 | echo "Test 2: CI=true (should skip silently)" 27 | echo "--------------------------------------" 28 | export CI=true 29 | node scripts/postinstall.js 30 | echo "[No output expected - skipped due to CI]" 31 | echo "" 32 | 33 | # Test 3: Opt-out flag (should skip silently) 34 | echo "Test 3: OPENSPEC_NO_COMPLETIONS=1 (should skip silently)" 35 | echo "--------------------------------------" 36 | unset CI 37 | export OPENSPEC_NO_COMPLETIONS=1 38 | node scripts/postinstall.js 39 | echo "[No output expected - skipped due to opt-out]" 40 | echo "" 41 | 42 | # Restore original environment 43 | if [ -n "$ORIGINAL_CI" ]; then 44 | export CI="$ORIGINAL_CI" 45 | else 46 | unset CI 47 | fi 48 | 49 | if [ -n "$ORIGINAL_OPENSPEC_NO_COMPLETIONS" ]; then 50 | export OPENSPEC_NO_COMPLETIONS="$ORIGINAL_OPENSPEC_NO_COMPLETIONS" 51 | else 52 | unset OPENSPEC_NO_COMPLETIONS 53 | fi 54 | 55 | echo "======================================" 56 | echo "All tests completed successfully!" 57 | echo "======================================" 58 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-adopt-delta-based-changes/specs/cli-diff/spec.md: -------------------------------------------------------------------------------- 1 | # CLI Diff Command - Changes 2 | 3 | ## REMOVED Requirements 4 | 5 | ### Requirement: Display Format 6 | 7 | The diff command SHALL display unified diff output in text format. 8 | 9 | **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. 10 | 11 | #### Scenario: Unified diff output (deprecated) 12 | 13 | - **WHEN** running `openspec diff ` 14 | - **THEN** show a unified text diff of files 15 | - **AND** include `+`/`-` prefixed lines representing additions and removals 16 | 17 | ## MODIFIED Requirements 18 | 19 | ### Requirement: Diff Output 20 | 21 | The command SHALL show a requirement-level comparison displaying only changed requirements. 22 | 23 | #### Scenario: Side-by-side comparison of changes 24 | 25 | - **WHEN** running `openspec diff ` 26 | - **THEN** display only requirements that have changed 27 | - **AND** show them in a side-by-side format that: 28 | - Clearly shows the current version on the left 29 | - Shows the future version on the right 30 | - Indicates new requirements (not in current) 31 | - Indicates removed requirements (not in future) 32 | - Aligns modified requirements for easy comparison 33 | 34 | ## ADDED Requirements 35 | 36 | ### Requirement: Validation 37 | 38 | The command SHALL validate that changes can be applied successfully. 39 | 40 | #### Scenario: Invalid delta references 41 | 42 | - **WHEN** delta references non-existent requirement 43 | - **THEN** show error message with specific requirement 44 | - **AND** continue showing other valid changes 45 | - **AND** clearly mark failed changes in the output -------------------------------------------------------------------------------- /test/commands/change.interactive-show.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, beforeEach, afterEach } from 'vitest'; 2 | import { promises as fs } from 'fs'; 3 | import path from 'path'; 4 | import { execSync } from 'child_process'; 5 | 6 | describe('change show (interactive behavior)', () => { 7 | const projectRoot = process.cwd(); 8 | const testDir = path.join(projectRoot, 'test-change-show-tmp'); 9 | const changesDir = path.join(testDir, 'openspec', 'changes'); 10 | const bin = path.join(projectRoot, 'bin', 'openspec.js'); 11 | 12 | 13 | beforeEach(async () => { 14 | await fs.mkdir(changesDir, { recursive: true }); 15 | const content = `# Change: Demo\n\n## Why\n\n## What Changes\n- x`; 16 | await fs.mkdir(path.join(changesDir, 'demo'), { recursive: true }); 17 | await fs.writeFile(path.join(changesDir, 'demo', 'proposal.md'), content, 'utf-8'); 18 | }); 19 | 20 | afterEach(async () => { 21 | await fs.rm(testDir, { recursive: true, force: true }); 22 | }); 23 | 24 | it('prints list hint and exits non-zero when no arg and non-interactive', () => { 25 | const originalCwd = process.cwd(); 26 | const originalEnv = { ...process.env }; 27 | try { 28 | process.chdir(testDir); 29 | process.env.OPEN_SPEC_INTERACTIVE = '0'; 30 | let err: any; 31 | try { 32 | execSync(`node ${bin} change show`, { encoding: 'utf-8' }); 33 | } catch (e) { err = e; } 34 | expect(err).toBeDefined(); 35 | expect(err.status).not.toBe(0); 36 | expect(err.stderr.toString()).toContain('Available IDs:'); 37 | expect(err.stderr.toString()).toContain('openspec change list'); 38 | } finally { 39 | process.chdir(originalCwd); 40 | process.env = originalEnv; 41 | } 42 | }); 43 | }); 44 | 45 | 46 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-29-update-markdown-parser-crlf/proposal.md: -------------------------------------------------------------------------------- 1 | # Update Markdown Parser CRLF Handling 2 | 3 | ## Problem 4 | 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. 5 | 6 | ## Solution 7 | - 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. 8 | - Reuse the normalized reader everywhere `MarkdownParser` is constructed to keep behavior consistent for validation, view, spec, and list flows. 9 | - 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`). 10 | - Update the `cli-validate` spec to codify the expectation that required sections are recognized regardless of line-ending style. 11 | 12 | ## Benefits 13 | - Restores correct validation behavior for Windows editors without requiring manual line-ending conversion. 14 | - Locks in the fix with targeted tests so future parser refactors keep cross-platform support. 15 | - Clarifies the spec so downstream work (e.g., cross-shell e2e plan) understands the non-negotiable behavior. 16 | 17 | ## Risks 18 | - 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). 19 | 20 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-structured-spec-format/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 3 | 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. 4 | 5 | ## What Changes 6 | 7 | **Specification Format Section** 8 | - From: No formal structure requirements for specifications 9 | - To: Structured format with `### Requirement:` and `#### Scenario:` headers 10 | - Reason: Visual consistency and parseability across all specs 11 | - Impact: Non-breaking - existing specs can migrate gradually 12 | 13 | **Keyword Formatting** 14 | - From: Inconsistent use of WHEN/THEN/AND keywords 15 | - To: Bold keywords (**WHEN**, **THEN**, **AND**) in scenario bullets 16 | - Reason: Improved readability and consistent visual hierarchy 17 | - Impact: Non-breaking - formatting enhancement only 18 | 19 | **Format Flexibility** 20 | - From: Implicit understanding that different content needs different formats 21 | - To: Explicit allowance for alternative formats (OpenAPI, JSON Schema, etc.) 22 | - Reason: Address concern that not all specs fit requirement/scenario pattern 23 | - Impact: Non-breaking - clarifies existing practice 24 | 25 | **Migration Guidelines** 26 | - From: No migration guidance 27 | - To: Documented gradual migration approach 28 | - Reason: Allows incremental adoption without disrupting existing specs 29 | - Impact: Non-breaking - opt-in migration as specs are modified 30 | 31 | ## Impact 32 | 33 | - Affected specs: openspec-conventions (enhancement to existing capability) 34 | - Affected code: None initially - this is a documentation standard enhancement 35 | - Migration: Gradual - existing specs migrate as they're modified 36 | - Tooling: Enables future parsing tools but doesn't require them 37 | -------------------------------------------------------------------------------- /src/core/configurators/qwen.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Qwen Code configurator for OpenSpec integration. 3 | * This class handles the configuration of Qwen Code as an AI tool within OpenSpec. 4 | * 5 | * @implements {ToolConfigurator} 6 | */ 7 | import path from 'path'; 8 | import { ToolConfigurator } from './base.js'; 9 | import { FileSystemUtils } from '../../utils/file-system.js'; 10 | import { TemplateManager } from '../templates/index.js'; 11 | import { OPENSPEC_MARKERS } from '../config.js'; 12 | 13 | /** 14 | * QwenConfigurator class provides integration with Qwen Code 15 | * by creating and managing the necessary configuration files. 16 | * Currently configures the QWEN.md file with OpenSpec instructions. 17 | */ 18 | export class QwenConfigurator implements ToolConfigurator { 19 | /** Display name for the Qwen Code tool */ 20 | name = 'Qwen Code'; 21 | 22 | /** Configuration file name for Qwen Code */ 23 | configFileName = 'QWEN.md'; 24 | 25 | /** Availability status for the Qwen Code tool */ 26 | isAvailable = true; 27 | 28 | /** 29 | * Configures the Qwen Code integration by creating or updating the QWEN.md file 30 | * with OpenSpec instructions and markers. 31 | * 32 | * @param {string} projectPath - The path to the project root 33 | * @param {string} _openspecDir - The path to the openspec directory (unused) 34 | * @returns {Promise} A promise that resolves when configuration is complete 35 | */ 36 | async configure(projectPath: string, _openspecDir: string): Promise { 37 | const filePath = path.join(projectPath, this.configFileName); 38 | const content = TemplateManager.getAgentsStandardTemplate(); 39 | 40 | await FileSystemUtils.updateFileWithMarkers( 41 | filePath, 42 | content, 43 | OPENSPEC_MARKERS.start, 44 | OPENSPEC_MARKERS.end 45 | ); 46 | } 47 | } -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-spec-commands/design.md: -------------------------------------------------------------------------------- 1 | # Design: Spec Commands 2 | 3 | ## Architecture Decisions 4 | 5 | ### Command Hierarchy 6 | We chose a subcommand pattern (`spec show`, `spec list`, `spec validate`) to: 7 | - Group related functionality under a common namespace 8 | - Enable future extensibility without polluting the top-level CLI 9 | - Maintain consistency with the planned `change` command structure 10 | 11 | ### JSON Schema Structure 12 | The spec JSON schema follows this structure: 13 | ```typescript 14 | { 15 | version: string, // Schema version for compatibility 16 | format: "spec", // Identifies this as a spec document 17 | sourcePath: string, // Original markdown file path 18 | id: string, // Spec identifier from filename 19 | title: string, // Human-readable title 20 | overview?: string, // Optional overview section 21 | requirements: Array<{ 22 | id: string, 23 | text: string, 24 | scenarios: Array<{ 25 | id: string, 26 | text: string 27 | }> 28 | }> 29 | } 30 | ``` 31 | 32 | **Rationale:** 33 | - Flat structure for requirements array (vs nested objects) for easier iteration 34 | - Scenarios nested within requirements to maintain relationship 35 | - Metadata fields (version, format, sourcePath) for tooling integration 36 | 37 | ### Parser Architecture 38 | - **Markdown-first approach**: Parse markdown headings rather than custom syntax 39 | - **Streaming parser**: Process line-by-line to handle large files efficiently 40 | - **Strict heading hierarchy**: Enforce ##/###/#### structure for consistency 41 | 42 | ### Validation Strategy 43 | - **Parse-time validation**: Catch structural issues during parsing 44 | - **Schema validation**: Use Zod for runtime type checking of parsed data 45 | - **Separate validation command**: Allow validation without full parsing/conversion -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-change-commands/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks (Phase 2: Builds on add-zod-validation) 2 | 3 | ## 1. Command Implementation 4 | - [x] 1.1 Create src/commands/change.ts 5 | - [x] 1.2 Import ChangeSchema and DeltaSchema from src/core/schemas/change.schema.ts 6 | - [x] 1.3 Import markdown parser from src/core/parsers/markdown-parser.ts 7 | - [x] 1.4 Import ChangeValidator from src/core/validation/validator.ts 8 | - [x] 1.5 Import JSON converter from src/core/converters/json-converter.ts 9 | - [x] 1.6 Implement show subcommand with JSON output using existing converter 10 | - [x] 1.7 Implement list subcommand 11 | - [x] 1.8 Implement validate subcommand using existing ChangeValidator 12 | - [x] 1.9 Add --requirements-only filtering option 13 | - [x] 1.10 Add --strict mode support (leveraging existing validation infrastructure) 14 | - [x] 1.11 Add --json flag for validation reports 15 | 16 | ## 2. Change-Specific Parser Extensions 17 | - [x] 2.1 Create src/core/parsers/change-parser.ts (extends base markdown parser) 18 | - [x] 2.2 Parse proposal structure (Why, What Changes sections) 19 | - [x] 2.3 Extract ADDED/MODIFIED/REMOVED/RENAMED sections 20 | - [x] 2.4 Parse delta operations within each section 21 | - [x] 2.5 Add tests for change parser 22 | 23 | ## 3. Legacy Compatibility 24 | - [x] 3.1 Update src/core/list.ts to add deprecation notice 25 | - [x] 3.2 Ensure existing list command continues to work 26 | - [x] 3.3 Add console warning for deprecated command usage 27 | 28 | ## 4. Integration 29 | - [x] 4.1 Register change command in src/cli/index.ts 30 | - [ ] 4.2 Add integration tests for all subcommands 31 | - [x] 4.3 Test JSON output for changes 32 | - [x] 4.4 Test legacy compatibility 33 | - [x] 4.5 Test validation with strict mode 34 | - [x] 4.6 Update CLI help documentation (add 'change' command to main help, document subcommands: show, list, validate) -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-change-commands/specs/cli-change/spec.md: -------------------------------------------------------------------------------- 1 | ## ADDED Requirements 2 | 3 | ### Requirement: Change Command 4 | 5 | The system SHALL provide a `change` command with subcommands for displaying, listing, and validating change proposals. 6 | 7 | #### Scenario: Show change as JSON 8 | 9 | - **WHEN** executing `openspec change show update-error --json` 10 | - **THEN** parse the markdown change file 11 | - **AND** extract change structure and deltas 12 | - **AND** output valid JSON to stdout 13 | 14 | #### Scenario: List all changes 15 | 16 | - **WHEN** executing `openspec change list` 17 | - **THEN** scan the openspec/changes directory 18 | - **AND** return list of all pending changes 19 | - **AND** support JSON output with `--json` flag 20 | 21 | #### Scenario: Show only requirement changes 22 | 23 | - **WHEN** executing `openspec change show update-error --requirements-only` 24 | - **THEN** display only the requirement changes (ADDED/MODIFIED/REMOVED/RENAMED) 25 | - **AND** exclude why and what changes sections 26 | 27 | #### Scenario: Validate change structure 28 | 29 | - **WHEN** executing `openspec change validate update-error` 30 | - **THEN** parse the change file 31 | - **AND** validate against Zod schema 32 | - **AND** ensure deltas are well-formed 33 | 34 | ### Requirement: Legacy Compatibility 35 | 36 | The system SHALL maintain backward compatibility with the existing `list` command while showing deprecation notices. 37 | 38 | #### Scenario: Legacy list command 39 | 40 | - **WHEN** executing `openspec list` 41 | - **THEN** display current list of changes (existing behavior) 42 | - **AND** show deprecation notice: "Note: 'openspec list' is deprecated. Use 'openspec change list' instead." 43 | 44 | #### Scenario: Legacy list with --all flag 45 | 46 | - **WHEN** executing `openspec list --all` 47 | - **THEN** display all changes (existing behavior) 48 | - **AND** show same deprecation notice -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-update-cli-init-root-agents/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 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. 3 | 4 | ## What Changes 5 | - 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. 6 | - 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. 7 | - Adjust CLI specs, prompts, and success messaging to reflect the new categories while keeping extend-mode behaviour consistent. 8 | - Update automated tests and fixtures to cover the unconditional stub creation and the reworked prompt flow. 9 | - Refresh documentation and onboarding snippets so they no longer describe the stub as opt-in and instead call out the new grouping. 10 | - Ensure `openspec update` continues to reconcile both `openspec/AGENTS.md` and the root stub, documenting the expected behaviour so mismatched setups self-heal. 11 | 12 | ## Impact 13 | - Affected specs: `cli-init`, `cli-update` 14 | - 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/` 15 | - Docs & assets: README, CHANGELOG, any setup guides that reference choosing the "AGENTS.md standard" option 16 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-13-add-archive-command/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## 1. Core Implementation 4 | - [ ] 1.1 Create `src/core/archive.ts` with ArchiveCommand class 5 | - [ ] 1.1.1 Implement change selection (interactive if not provided) 6 | - [ ] 1.1.2 Implement incomplete task checking from tasks.md 7 | - [ ] 1.1.3 Implement confirmation prompt for incomplete tasks 8 | - [ ] 1.1.4 Implement spec update functionality 9 | - [ ] 1.1.4.1 Detect specs in change directory 10 | - [ ] 1.1.4.2 Compare with existing main specs 11 | - [ ] 1.1.4.3 Display summary of new vs updated specs 12 | - [ ] 1.1.4.4 Show confirmation prompt for spec updates 13 | - [ ] 1.1.4.5 Copy specs to main spec directory 14 | - [ ] 1.1.5 Implement archive move with date prefixing 15 | - [ ] 1.1.6 Support --yes flag to skip confirmations 16 | 17 | ## 2. CLI Integration 18 | - [ ] 2.1 Add archive command to `src/cli/index.ts` 19 | - [ ] 2.1.1 Import ArchiveCommand 20 | - [ ] 2.1.2 Register command with commander 21 | - [ ] 2.1.3 Add --yes/-y flag option 22 | - [ ] 2.1.4 Add proper error handling 23 | 24 | ## 3. Error Handling 25 | - [ ] 3.1 Handle missing openspec/changes/ directory 26 | - [ ] 3.2 Handle change not found 27 | - [ ] 3.3 Handle archive target already exists 28 | - [ ] 3.4 Handle user cancellation 29 | 30 | ## 4. Testing 31 | - [ ] 4.1 Test with fully completed change 32 | - [ ] 4.2 Test with incomplete tasks (warning shown) 33 | - [ ] 4.3 Test interactive selection mode 34 | - [ ] 4.4 Test duplicate archive prevention 35 | - [ ] 4.5 Test spec update functionality 36 | - [ ] 4.5.1 Test creating new specs 37 | - [ ] 4.5.2 Test updating existing specs 38 | - [ ] 4.5.3 Test confirmation prompt display 39 | - [ ] 4.5.4 Test declining confirmation (no changes made) 40 | - [ ] 4.5.5 Test --yes flag skips confirmation 41 | 42 | ## 5. Build and Validation 43 | - [ ] 5.1 Ensure TypeScript compilation succeeds 44 | - [ ] 5.2 Test command execution -------------------------------------------------------------------------------- /test/commands/validate.enriched-output.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, beforeEach, afterEach } from 'vitest'; 2 | import { promises as fs } from 'fs'; 3 | import path from 'path'; 4 | import { execSync } from 'child_process'; 5 | 6 | describe('validate command enriched human output', () => { 7 | const projectRoot = process.cwd(); 8 | const testDir = path.join(projectRoot, 'test-validate-enriched-tmp'); 9 | const changesDir = path.join(testDir, 'openspec', 'changes'); 10 | const bin = path.join(projectRoot, 'bin', 'openspec.js'); 11 | 12 | 13 | beforeEach(async () => { 14 | await fs.mkdir(changesDir, { recursive: true }); 15 | }); 16 | 17 | afterEach(async () => { 18 | await fs.rm(testDir, { recursive: true, force: true }); 19 | }); 20 | 21 | it('prints Next steps footer and guidance on invalid change', () => { 22 | const changeContent = `# Test Change\n\n## Why\nThis is a sufficiently long explanation to pass the why length requirement for validation purposes.\n\n## What Changes\nThere are changes proposed, but no delta specs provided yet.`; 23 | const changeId = 'c-next-steps'; 24 | const changePath = path.join(changesDir, changeId); 25 | execSync(`mkdir -p ${changePath}`); 26 | execSync(`bash -lc "cat > ${path.join(changePath, 'proposal.md')} <<'EOF'\n${changeContent}\nEOF"`); 27 | 28 | const originalCwd = process.cwd(); 29 | try { 30 | process.chdir(testDir); 31 | let code = 0; 32 | let stderr = ''; 33 | try { 34 | execSync(`node ${bin} change validate ${changeId}`, { encoding: 'utf-8', stdio: 'pipe' }); 35 | } catch (e: any) { 36 | code = e?.status ?? 1; 37 | stderr = e?.stderr?.toString?.() ?? ''; 38 | } 39 | expect(code).not.toBe(0); 40 | expect(stderr).toContain('has issues'); 41 | expect(stderr).toContain('Next steps:'); 42 | expect(stderr).toContain('openspec change show'); 43 | } finally { 44 | process.chdir(originalCwd); 45 | } 46 | }); 47 | }); 48 | 49 | 50 | -------------------------------------------------------------------------------- /test/commands/change.interactive-validate.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, beforeEach, afterEach } from 'vitest'; 2 | import { promises as fs } from 'fs'; 3 | import path from 'path'; 4 | import { execSync } from 'child_process'; 5 | 6 | // Note: We cannot truly simulate TTY prompts in this test runner easily. 7 | // Instead, we verify non-interactive fallback behavior and basic invocation. 8 | 9 | describe('change validate (interactive behavior)', () => { 10 | const projectRoot = process.cwd(); 11 | const testDir = path.join(projectRoot, 'test-change-validate-tmp'); 12 | const changesDir = path.join(testDir, 'openspec', 'changes'); 13 | const bin = path.join(projectRoot, 'bin', 'openspec.js'); 14 | 15 | 16 | beforeEach(async () => { 17 | await fs.mkdir(changesDir, { recursive: true }); 18 | const content = `# Change: Demo\n\n## Why\nBecause reasons that are sufficiently long.\n\n## What Changes\n- **spec-x:** Add something`; 19 | await fs.mkdir(path.join(changesDir, 'demo'), { recursive: true }); 20 | await fs.writeFile(path.join(changesDir, 'demo', 'proposal.md'), content, 'utf-8'); 21 | }); 22 | 23 | afterEach(async () => { 24 | await fs.rm(testDir, { recursive: true, force: true }); 25 | }); 26 | 27 | it('prints list hint and exits non-zero when no arg and non-interactive', () => { 28 | const originalCwd = process.cwd(); 29 | const originalEnv = { ...process.env }; 30 | try { 31 | process.chdir(testDir); 32 | process.env.OPEN_SPEC_INTERACTIVE = '0'; 33 | let err: any; 34 | try { 35 | execSync(`node ${bin} change validate`, { encoding: 'utf-8' }); 36 | } catch (e) { err = e; } 37 | expect(err).toBeDefined(); 38 | expect(err.status).not.toBe(0); 39 | expect(err.stderr.toString()).toContain('Available IDs:'); 40 | expect(err.stderr.toString()).toContain('openspec change list'); 41 | } finally { 42 | process.chdir(originalCwd); 43 | process.env = originalEnv; 44 | } 45 | }); 46 | }); 47 | 48 | 49 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-fix-update-tool-selection/proposal.md: -------------------------------------------------------------------------------- 1 | # Fix Update Command Tool Selection 2 | 3 | ## Problem 4 | 5 | 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. 6 | 7 | Additionally, different team members may use different AI tools, so we cannot rely on a shared configuration file. 8 | 9 | ## Solution 10 | 11 | Modify the update command to: 12 | 1. Only update AI tool configuration files that already exist 13 | 2. Never create new AI tool configuration files 14 | 3. Always update the core OpenSpec files (README.md, etc.) 15 | 16 | ## Implementation 17 | 18 | - Remove hardcoded CLAUDE.md update from update command 19 | - Implement file existence check before updating any AI tool config 20 | - Update each existing AI tool config file with its appropriate markers 21 | - No configuration file needed (avoids team conflicts) 22 | 23 | ## Success Criteria 24 | 25 | - Update command only modifies existing AI tool configuration files 26 | - No new AI tool files created during update 27 | - Team members can use different AI tools without conflicts 28 | - Existing projects continue to work (backward compatibility) 29 | 30 | ## Why 31 | 32 | 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. 33 | 34 | ## What Changes 35 | 36 | - **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. 37 | 38 | ## ADDED Requirements 39 | 40 | Removed from proposal to follow conventions. See `specs/cli-update/spec.md` for the delta requirements content. -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-add-codex-slash-command-support/tasks.md: -------------------------------------------------------------------------------- 1 | ## 1. CLI integration 2 | - [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. 3 | - [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. 4 | // (No helper command required) 5 | - [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. 6 | 7 | ## 2. Prompt templates 8 | - [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. 9 | - [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. 10 | 11 | ## 3. Update support & tests 12 | - [x] 3.1 Update the `openspec update` flow to refresh existing Codex prompts without creating new ones when files are missing. 13 | - [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. 14 | - [x] 3.3 Document Codex's global-only discovery and automatic installation in README and CHANGELOG. 15 | - [x] 3.3 Confirm error handling surfaces clear paths when the CLI cannot write to the Codex prompt directory (permissions, missing home directory, etc.). 16 | 17 | ## 4. Documentation 18 | - [x] 4.1 Document Codex slash-command support in the README and changelog alongside other assistant integrations. 19 | - [x] 4.2 Add a release note snippet that points Codex users to the generated `/openspec-proposal`, `/openspec-apply`, and `/openspec-archive` commands. 20 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-add-kilocode-workflows/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | - 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.\\ 3 | ([Workflows | Kilo Code Docs](https://kilocode.ai/docs/features/slash-commands/workflows)) 4 | - 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. 5 | - 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. 6 | 7 | ## What Changes 8 | - 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. 9 | - 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). 10 | - Teach `openspec update` to refresh existing Kilo Code workflows (and only those that already exist) using the shared slash-command templates. 11 | - Update documentation, release notes, and integration tests so the new workflow support is covered alongside Claude, Cursor, OpenCode, and Windsurf. 12 | 13 | ## Impact 14 | - Specs: `cli-init`, `cli-update` 15 | - Code: `src/core/config.ts`, `src/core/configurators/(registry|slash/*)`, `src/core/templates/slash-command-templates.ts`, CLI wiring for tool summaries 16 | - Tests: init/update workflow coverage, regression for marker preservation in `.kilocode/workflows/` 17 | - Docs: README / CHANGELOG updates advertising Kilo Code workflow support 18 | -------------------------------------------------------------------------------- /src/core/converters/json-converter.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'fs'; 2 | import path from 'path'; 3 | import { MarkdownParser } from '../parsers/markdown-parser.js'; 4 | import { ChangeParser } from '../parsers/change-parser.js'; 5 | import { Spec, Change } from '../schemas/index.js'; 6 | 7 | export class JsonConverter { 8 | convertSpecToJson(filePath: string): string { 9 | const content = readFileSync(filePath, 'utf-8'); 10 | const parser = new MarkdownParser(content); 11 | const specName = this.extractNameFromPath(filePath); 12 | 13 | const spec = parser.parseSpec(specName); 14 | 15 | const jsonSpec = { 16 | ...spec, 17 | metadata: { 18 | ...spec.metadata, 19 | sourcePath: filePath, 20 | }, 21 | }; 22 | 23 | return JSON.stringify(jsonSpec, null, 2); 24 | } 25 | 26 | async convertChangeToJson(filePath: string): Promise { 27 | const content = readFileSync(filePath, 'utf-8'); 28 | const changeName = this.extractNameFromPath(filePath); 29 | const changeDir = path.dirname(filePath); 30 | const parser = new ChangeParser(content, changeDir); 31 | 32 | const change = await parser.parseChangeWithDeltas(changeName); 33 | 34 | const jsonChange = { 35 | ...change, 36 | metadata: { 37 | ...change.metadata, 38 | sourcePath: filePath, 39 | }, 40 | }; 41 | 42 | return JSON.stringify(jsonChange, null, 2); 43 | } 44 | 45 | private extractNameFromPath(filePath: string): string { 46 | const normalizedPath = filePath.replaceAll('\\', '/'); 47 | const parts = normalizedPath.split('/'); 48 | 49 | for (let i = parts.length - 1; i >= 0; i--) { 50 | if (parts[i] === 'specs' || parts[i] === 'changes') { 51 | if (i < parts.length - 1) { 52 | return parts[i + 1]; 53 | } 54 | } 55 | } 56 | 57 | const fileName = parts[parts.length - 1] ?? ''; 58 | const dotIndex = fileName.lastIndexOf('.'); 59 | return dotIndex > 0 ? fileName.slice(0, dotIndex) : fileName; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /openspec/project.md: -------------------------------------------------------------------------------- 1 | # OpenSpec Project Overview 2 | 3 | A minimal CLI tool that helps developers set up OpenSpec file structures and keep AI instructions updated. The AI tools themselves handle all the change management complexity by working directly with markdown files. 4 | 5 | ## Technology Stack 6 | - Language: TypeScript 7 | - Runtime: Node.js (≥20.19.0, ESM modules) 8 | - Package Manager: pnpm 9 | - CLI Framework: Commander.js 10 | - User Interaction: @inquirer/prompts 11 | - Distribution: npm package 12 | 13 | ## Project Structure 14 | ``` 15 | src/ 16 | ├── cli/ # CLI command implementations 17 | ├── core/ # Core OpenSpec logic (templates, structure) 18 | └── utils/ # Shared utilities (file operations, rollback) 19 | 20 | dist/ # Compiled output (gitignored) 21 | ``` 22 | 23 | ## Conventions 24 | - TypeScript strict mode enabled 25 | - Async/await for all asynchronous operations 26 | - Minimal dependencies principle 27 | - Clear separation of CLI, core logic, and utilities 28 | - AI-friendly code with descriptive names 29 | 30 | ## Error Handling 31 | - Let errors bubble up to CLI level for consistent user messaging 32 | - Use native Error types with descriptive messages 33 | - Exit with appropriate codes: 0 (success), 1 (general error), 2 (misuse) 34 | - No try-catch in utility functions, handle at command level 35 | 36 | ## Logging 37 | - Use console methods directly (no logging library) 38 | - console.log() for normal output 39 | - console.error() for errors (outputs to stderr) 40 | - No verbose/debug modes initially (keep it simple) 41 | 42 | ## Testing Strategy 43 | - Manual testing via `pnpm link` during development 44 | - Smoke tests for critical paths only (init, help commands) 45 | - No unit tests initially - add when complexity grows 46 | - Test commands: `pnpm test:smoke` (when added) 47 | 48 | ## Development Workflow 49 | - Use pnpm for all package management 50 | - Run `pnpm run build` to compile TypeScript 51 | - Run `pnpm run dev` for development mode 52 | - Test locally with `pnpm link` 53 | - Follow OpenSpec's own change-driven development process -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-add-github-copilot-prompts/tasks.md: -------------------------------------------------------------------------------- 1 | ## Implementation Tasks 2 | 3 | - [x] Create `src/core/configurators/slash/github-copilot.ts` implementing `SlashCommandConfigurator` base class 4 | - Implement `getRelativePath()` to return `.github/prompts/openspec-{proposal,apply,archive}.prompt.md` 5 | - Implement `getFrontmatter()` to generate YAML frontmatter with `description` field and include `$ARGUMENTS` placeholder 6 | - Implement `generateAll()` to create `.github/prompts/` directory and write three prompt files with frontmatter, markers, and shared template bodies 7 | - Implement `updateExisting()` to refresh only the managed block between markers while preserving frontmatter 8 | - Set `toolId = "github-copilot"` and `isAvailable = true` 9 | 10 | - [x] Register GitHub Copilot configurator in `src/core/configurators/slash/registry.ts` 11 | - Import `GitHubCopilotSlashCommandConfigurator` 12 | - Add to `SLASH_COMMAND_CONFIGURATORS` array 13 | - Update tool picker display name to "GitHub Copilot" 14 | 15 | - [x] Update `src/core/init.ts` to include GitHub Copilot in the AI tool selection prompt 16 | - Add GitHub Copilot to the available tools list with detection for existing `.github/prompts/openspec-*.prompt.md` files 17 | - Display "(already configured)" when prompt files exist 18 | 19 | - [x] Update `src/core/update.ts` to refresh GitHub Copilot prompts when they exist 20 | - Call `updateExisting()` for GitHub Copilot configurator when `.github/prompts/` contains OpenSpec prompt files 21 | 22 | - [x] Add integration tests for GitHub Copilot slash command generation 23 | - Test `generateAll()` creates three prompt files with correct structure (frontmatter + markers + body) 24 | - Test `updateExisting()` preserves frontmatter and only updates managed blocks 25 | - Test that missing prompt files are not created during update 26 | 27 | - [x] Update documentation 28 | - Add GitHub Copilot to README slash-command support table 29 | - Document `.github/prompts/` as the discovery location 30 | - Add CHANGELOG entry for GitHub Copilot support 31 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-09-12-add-view-dashboard-command/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks 2 | 3 | ## Design Phase 4 | - [x] Research existing list command implementation 5 | - [x] Design dashboard layout and information architecture 6 | - [x] Choose appropriate command verb (`view`) 7 | - [x] Define visual elements (progress bars, colors, layout) 8 | 9 | ## Core Implementation 10 | - [x] Create ViewCommand class in `/src/core/view.ts` 11 | - [x] Implement getChangesData method for fetching change information 12 | - [x] Implement getSpecsData method for fetching spec information 13 | - [x] Implement displaySummary method for summary metrics 14 | - [x] Add progress bar visualization with Unicode characters 15 | - [x] Implement color coding using chalk 16 | 17 | ## Integration 18 | - [x] Import ViewCommand in CLI index 19 | - [x] Register `openspec view` command with commander 20 | - [x] Add proper error handling and ora spinner integration 21 | - [x] Ensure command appears in help documentation 22 | 23 | ## Data Processing 24 | - [x] Reuse TaskProgress utilities for change progress 25 | - [x] Integrate MarkdownParser for spec requirement counting 26 | - [x] Handle async operations for file system access 27 | - [x] Sort specifications by requirement count 28 | 29 | ## Testing and Validation 30 | - [x] Build project successfully with new command 31 | - [x] Test command with sample data 32 | - [x] Verify correct requirement counts match list --specs 33 | - [x] Test progress bar display for various completion states 34 | - [x] Run existing test suite to ensure no regressions 35 | - [x] Verify TypeScript compilation with no errors 36 | 37 | ## Documentation 38 | - [x] Add command description in CLI help 39 | - [x] Create change proposal documentation 40 | - [x] Update README with view command example (if needed) 41 | - [x] Add view command to user documentation (if exists) 42 | 43 | ## Polish 44 | - [x] Ensure consistent formatting and alignment 45 | - [x] Add helpful footer text referencing list commands 46 | - [x] Optimize for terminal width considerations 47 | - [x] Review and refine color choices for accessibility -------------------------------------------------------------------------------- /src/core/configurators/registry.ts: -------------------------------------------------------------------------------- 1 | import { ToolConfigurator } from './base.js'; 2 | import { ClaudeConfigurator } from './claude.js'; 3 | import { ClineConfigurator } from './cline.js'; 4 | import { CodeBuddyConfigurator } from './codebuddy.js'; 5 | import { CostrictConfigurator } from './costrict.js'; 6 | import { QoderConfigurator } from './qoder.js'; 7 | import { IflowConfigurator } from './iflow.js'; 8 | import { AgentsStandardConfigurator } from './agents.js'; 9 | import { QwenConfigurator } from './qwen.js'; 10 | 11 | export class ToolRegistry { 12 | private static tools: Map = new Map(); 13 | 14 | static { 15 | const claudeConfigurator = new ClaudeConfigurator(); 16 | const clineConfigurator = new ClineConfigurator(); 17 | const codeBuddyConfigurator = new CodeBuddyConfigurator(); 18 | const costrictConfigurator = new CostrictConfigurator(); 19 | const qoderConfigurator = new QoderConfigurator(); 20 | const iflowConfigurator = new IflowConfigurator(); 21 | const agentsConfigurator = new AgentsStandardConfigurator(); 22 | const qwenConfigurator = new QwenConfigurator(); 23 | // Register with the ID that matches the checkbox value 24 | this.tools.set('claude', claudeConfigurator); 25 | this.tools.set('cline', clineConfigurator); 26 | this.tools.set('codebuddy', codeBuddyConfigurator); 27 | this.tools.set('costrict', costrictConfigurator); 28 | this.tools.set('qoder', qoderConfigurator); 29 | this.tools.set('iflow', iflowConfigurator); 30 | this.tools.set('agents', agentsConfigurator); 31 | this.tools.set('qwen', qwenConfigurator); 32 | } 33 | 34 | static register(tool: ToolConfigurator): void { 35 | this.tools.set(tool.name.toLowerCase().replace(/\s+/g, '-'), tool); 36 | } 37 | 38 | static get(toolId: string): ToolConfigurator | undefined { 39 | return this.tools.get(toolId); 40 | } 41 | 42 | static getAll(): ToolConfigurator[] { 43 | return Array.from(this.tools.values()); 44 | } 45 | 46 | static getAvailable(): ToolConfigurator[] { 47 | return this.getAll().filter(tool => tool.isAvailable); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/core/configurators/qoder.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { ToolConfigurator } from './base.js'; 3 | import { FileSystemUtils } from '../../utils/file-system.js'; 4 | import { TemplateManager } from '../templates/index.js'; 5 | import { OPENSPEC_MARKERS } from '../config.js'; 6 | 7 | /** 8 | * Qoder AI Tool Configurator 9 | * 10 | * Configures OpenSpec integration for Qoder AI coding assistant. 11 | * Creates and manages QODER.md configuration file with OpenSpec instructions. 12 | * 13 | * @implements {ToolConfigurator} 14 | */ 15 | export class QoderConfigurator implements ToolConfigurator { 16 | /** Display name for the Qoder tool */ 17 | name = 'Qoder'; 18 | 19 | /** Configuration file name at project root */ 20 | configFileName = 'QODER.md'; 21 | 22 | /** Indicates tool is available for configuration */ 23 | isAvailable = true; 24 | 25 | /** 26 | * Configure Qoder integration for a project 27 | * 28 | * Creates or updates QODER.md file with OpenSpec instructions. 29 | * Uses Claude-compatible template for instruction content. 30 | * Wrapped with OpenSpec markers for future updates. 31 | * 32 | * @param {string} projectPath - Absolute path to project root directory 33 | * @param {string} openspecDir - Path to openspec directory (unused but required by interface) 34 | * @returns {Promise} Resolves when configuration is complete 35 | */ 36 | async configure(projectPath: string, openspecDir: string): Promise { 37 | // Construct full path to QODER.md at project root 38 | const filePath = path.join(projectPath, this.configFileName); 39 | 40 | // Get Claude-compatible instruction template 41 | // This ensures Qoder receives the same high-quality OpenSpec instructions 42 | const content = TemplateManager.getClaudeTemplate(); 43 | 44 | // Write or update file with managed content between markers 45 | // This allows future updates to refresh instructions automatically 46 | await FileSystemUtils.updateFileWithMarkers( 47 | filePath, 48 | content, 49 | OPENSPEC_MARKERS.start, 50 | OPENSPEC_MARKERS.end 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-06-add-init-command/tasks.md: -------------------------------------------------------------------------------- 1 | # Implementation Tasks for Init Command 2 | 3 | ## 1. Core Infrastructure 4 | - [x] 1.1 Create src/utils/file-system.ts with directory/file creation utilities 5 | - [x] 1.2 Create src/core/templates/index.ts for template management 6 | - [x] 1.3 Create src/core/init.ts with main initialization logic 7 | - [x] 1.4 Create src/core/config.ts for configuration management 8 | 9 | ## 2. Template Files 10 | - [x] 2.1 Create src/core/templates/readme-template.ts with OpenSpec README content 11 | - [x] 2.2 Create src/core/templates/project-template.ts with customizable project.md 12 | - [x] 2.3 Create src/core/templates/claude-template.ts for CLAUDE.md content with markers 13 | 14 | ## 3. AI Tool Configurators 15 | - [x] 3.1 Create src/core/configurators/base.ts with ToolConfigurator interface 16 | - [x] 3.2 Create src/core/configurators/claude.ts for Claude Code configuration 17 | - [x] 3.3 Create src/core/configurators/registry.ts for tool registration 18 | - [x] 3.4 Implement marker-based file updates for existing configurations 19 | 20 | ## 4. Init Command Implementation 21 | - [x] 4.1 Add init command to src/cli/index.ts using Commander 22 | - [x] 4.2 Implement AI tool selection with multi-select prompt (Claude Code available, others "coming soon") - requires at least one selection 23 | - [x] 4.3 Add validation for existing OpenSpec directories with helpful error message 24 | - [x] 4.4 Implement directory structure creation 25 | - [x] 4.5 Implement file generation with templates and markers 26 | 27 | ## 5. User Experience 28 | - [x] 5.1 Add colorful console output for better UX 29 | - [x] 5.2 Implement progress indicators (Step 1/3, 2/3, 3/3) 30 | - [x] 5.3 Add success message with actionable next steps (edit project.md, create first change) 31 | - [x] 5.4 Add error handling with helpful messages 32 | 33 | ## 6. Testing and Documentation 34 | - [x] 6.1 Add unit tests for file system utilities 35 | - [x] 6.2 Add unit tests for marker-based file updates 36 | - [x] 6.3 Add integration tests for init command 37 | - [x] 6.4 Update package.json with proper bin configuration 38 | - [x] 6.5 Test the built CLI command end-to-end -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-22-add-archive-command-arguments/specs/cli-update/spec.md: -------------------------------------------------------------------------------- 1 | # CLI Update Specification Delta 2 | 3 | ## MODIFIED Requirements 4 | 5 | ### Requirement: Slash Command Updates 6 | 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. 7 | 8 | #### Scenario: Updating slash commands for OpenCode 9 | - **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` 10 | - **THEN** refresh each file using shared templates 11 | - **AND** ensure templates include instructions for the relevant workflow stage 12 | - **AND** ensure the archive command includes `$ARGUMENTS` placeholder in frontmatter for accepting change ID arguments 13 | 14 | ### Requirement: Archive Command Argument Support 15 | The archive slash command template SHALL support optional change ID arguments for tools that support `$ARGUMENTS` placeholder. 16 | 17 | #### Scenario: Archive command with change ID argument 18 | - **WHEN** a user invokes `/openspec:archive ` with a change ID 19 | - **THEN** the template SHALL instruct the AI to validate the provided change ID against `openspec list` 20 | - **AND** use the provided change ID for archiving if valid 21 | - **AND** fail fast if the provided change ID doesn't match an archivable change 22 | 23 | #### Scenario: Archive command without argument (backward compatibility) 24 | - **WHEN** a user invokes `/openspec:archive` without providing a change ID 25 | - **THEN** the template SHALL instruct the AI to identify the change ID from context or by running `openspec list` 26 | - **AND** proceed with the existing behavior (maintaining backward compatibility) 27 | 28 | #### Scenario: OpenCode archive template generation 29 | - **WHEN** generating the OpenCode archive slash command file 30 | - **THEN** include the `$ARGUMENTS` placeholder in the frontmatter 31 | - **AND** wrap it in a clear structure like `\n $ARGUMENTS\n` to indicate the expected argument 32 | - **AND** include validation steps in the template body to check if the change ID is valid 33 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-10-14-add-windsurf-workflows/proposal.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | - 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.\ 3 | ([Windsurf Workflows documentation](https://docs.windsurf.com/windsurf/cascade/workflows)) 4 | - 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.\ 5 | ("Custom Workflows" section, [Windsurf changelog](https://windsurf.com/changelog)) 6 | - 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. 7 | 8 | ## What Changes 9 | - 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. 10 | - 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. 11 | - Ensure `openspec update` refreshes existing Windsurf workflows (and only those that already exist) in-place, mirroring current behaviour for other editors. 12 | - Extend unit tests for init/update to cover Windsurf generation and updates, and update the README/tooling docs to advertise Windsurf support. 13 | 14 | ## Impact 15 | - Specs: `cli-init`, `cli-update` 16 | - Code: `src/core/configurators/slash/*`, `src/core/templates/slash-command-templates.ts`, CLI prompts, README 17 | - Tests: init/update integration coverage for Windsurf workflows 18 | -------------------------------------------------------------------------------- /openspec/changes/archive/2025-08-19-add-change-commands/design.md: -------------------------------------------------------------------------------- 1 | # Design: Change Commands 2 | 3 | ## Architecture Decisions 4 | 5 | ### Command Structure 6 | Similar to spec commands, we use subcommands (`change show`, `change list`, `change validate`) for: 7 | - Consistency with spec command pattern 8 | - Clear separation of concerns 9 | - Future extensibility for change management features 10 | 11 | ### JSON Schema for Changes 12 | ```typescript 13 | { 14 | version: string, // Schema version 15 | format: "change", // Identifies as change document 16 | sourcePath: string, // Original markdown file path 17 | id: string, // Change identifier 18 | title: string, // Change title 19 | why: string, // Motivation section 20 | whatChanges: Array<{ 21 | type: "ADDED" | "MODIFIED" | "REMOVED" | "RENAMED", 22 | deltas: Array<{ 23 | specId: string, 24 | description: string, 25 | requirements?: Array // Only for ADDED/MODIFIED 26 | }> 27 | }> 28 | } 29 | ``` 30 | 31 | **Rationale:** 32 | - Group deltas by operation type for clearer organization 33 | - Optional requirements field (only relevant for ADDED/MODIFIED) 34 | - Reuse RequirementSchema from spec commands for consistency 35 | 36 | ### Delta Operations 37 | **Four operation types:** 38 | 1. **ADDED**: New requirements added to specs 39 | 2. **MODIFIED**: Changes to existing requirements 40 | 3. **REMOVED**: Requirements being deleted 41 | 4. **RENAMED**: Spec identifier changes 42 | 43 | **Design choice:** Explicit operation types rather than diff-based approach for: 44 | - Human readability in markdown 45 | - Clear intent communication 46 | - Easier validation and tooling 47 | 48 | ### Dependency on Spec Commands 49 | - **Shared schemas**: RequirementSchema and ScenarioSchema reused 50 | - **Implementation order**: spec commands must be implemented first 51 | - **Common parser utilities**: Share markdown parsing logic 52 | 53 | ### Legacy Compatibility 54 | - Keep existing `list` command functional with deprecation warning 55 | - Migration path: `list` → `change list` with same functionality 56 | - Gradual transition to avoid breaking existing workflows --------------------------------------------------------------------------------