Skip to content

Commit e4548bc

Browse files
authored
Merge pull request #60 from Fission-AI/codex/add-custom-slash-command-support-for-openspec
docs: add slash command support proposal
2 parents 98d90cc + 68fc049 commit e4548bc

File tree

9 files changed

+248
-0
lines changed

9 files changed

+248
-0
lines changed

openspec/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ After deployment, create separate PR to:
8787
openspec list # List active changes
8888
openspec list --specs # List specifications
8989
openspec show [item] # Display change or spec
90+
openspec diff [change] # Show spec differences
9091
openspec validate [item] # Validate changes or specs
9192
openspec archive [change] # Archive after deployment
9293

@@ -255,6 +256,19 @@ Every requirement MUST have at least one scenario.
255256

256257
Headers matched with `trim(header)` - whitespace ignored.
257258

259+
#### When to use ADDED vs MODIFIED
260+
- ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding "Slash Command Configuration") rather than altering the semantics of an existing requirement.
261+
- MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.
262+
- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.
263+
264+
Common pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you aren’t explicitly changing the existing requirement, add a new requirement under ADDED instead.
265+
266+
Authoring a MODIFIED requirement correctly:
267+
1) Locate the existing requirement in `openspec/specs/<capability>/spec.md`.
268+
2) Copy the entire requirement block (from `### Requirement: ...` through its scenarios).
269+
3) Paste it under `## MODIFIED Requirements` and edit to reflect the new behavior.
270+
4) Ensure the header text matches exactly (whitespace-insensitive) and keep at least one `#### Scenario:`.
271+
258272
Example for RENAMED:
259273
```markdown
260274
## RENAMED Requirements
@@ -425,6 +439,7 @@ Only add complexity with:
425439
```bash
426440
openspec list # What's in progress?
427441
openspec show [item] # View details
442+
openspec diff [change] # What's changing?
428443
openspec validate --strict # Is it correct?
429444
openspec archive [change] # Mark complete
430445
```
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Add Slash Command Support for Coding Agents
2+
3+
## Summary
4+
- Enable OpenSpec to generate and update custom slash commands for supported coding agents (Claude Code and Cursor).
5+
- Provide three slash commands aligned with OpenSpec's workflow: proposal (start a change proposal), apply (implement), and archive.
6+
- Share slash command templating between agents to make future extensions simple.
7+
8+
## Motivation
9+
Developers use different coding agents and editors. Having consistent slash commands across tools for the OpenSpec workflow reduces friction and ensures a standard way to trigger the workflow. Supporting both Claude Code and Cursor now lays a foundation for future agents that introduce slash command features.
10+
11+
## Proposal
12+
1. During `openspec init`, when a user selects a supported tool, generate slash command configuration for three OpenSpec workflow stages:
13+
- Claude (namespaced): `/openspec/proposal`, `/openspec/apply`, `/openspec/archive`.
14+
- Cursor (flat, prefixed): `/openspec-proposal`, `/openspec-apply`, `/openspec-archive`.
15+
- Semantics:
16+
- Create – scaffold a change (ID, `proposal.md`, `tasks.md`, delta specs); validate strictly.
17+
- Apply – implement an approved change; complete tasks; validate strictly.
18+
- Archive – archive after deployment; update specs if needed.
19+
- Each command file MUST embed concise, step-by-step instructions sourced from `openspec/README.md` (see Template Content section).
20+
2. Store slash command files per tool:
21+
- Claude Code: `.claude/commands/openspec/{proposal,apply,archive}.md`
22+
- Cursor: `.cursor/commands/{openspec-proposal,openspec-apply,openspec-archive}.md`
23+
- Ensure nested directories are created.
24+
3. Command file format and metadata:
25+
- Use Markdown with optional YAML frontmatter for tool metadata (name/title, description, category/tags) when supported by the tool.
26+
- Place OpenSpec markers around the body only, never inside frontmatter.
27+
- Keep the visible slash name, file name, and any frontmatter `name`/`id` consistently aligned (e.g., `proposal`, `openspec-proposal`).
28+
- Namespacing: categorize these under “OpenSpec” and prefer unique IDs (e.g., `openspec-proposal`) to avoid collisions.
29+
4. Centralize templates: define command bodies once and reuse across tools; apply minimal per-tool wrappers (frontmatter, categories, filenames).
30+
5. During `openspec update`, refresh only existing slash command files (per-file basis) within markers; do not create missing files or new tools.
31+
32+
## Design Ideas
33+
- Introduce `SlashCommandConfigurator` to manage multiple files per tool.
34+
- Expose targets rather than a single `configFileName` (e.g., `getTargets(): Array<{ path: string; kind: 'slash'; id: string }>`).
35+
- Provide `generateAll(projectPath, openspecDir)` for init and `updateExisting(projectPath, openspecDir)` for update.
36+
- Per-tool adapters add only frontmatter and pathing; bodies come from shared templates.
37+
- Templates live in `TemplateManager` with helpers that extract concise, authoritative snippets from `openspec/README.md`.
38+
- Update flow logs per-file results so users see exactly which slash files were refreshed.
39+
40+
### Marker Placement
41+
- Markers MUST wrap only the Markdown body contents:
42+
- Frontmatter (if present) goes first.
43+
- Then `<!-- OPENSPEC:START -->` … body … `<!-- OPENSPEC:END -->`.
44+
- Avoid inserting markers into the YAML block to prevent parse errors.
45+
46+
### Idempotency and Creation Rules
47+
- `init`: create all three files for the chosen tool(s) once; subsequent `init` runs are no-ops for existing files.
48+
- `update`: refresh only files that exist; skip missing ones without creating new files.
49+
- Directory creation for `.claude/commands/openspec/` and `.cursor/commands/` is the configurator’s responsibility.
50+
51+
### Command Naming & UX
52+
- Claude Code: use namespacing in the slash itself for readability and grouping: `/openspec/proposal`, `/openspec/apply`, `/openspec/archive`.
53+
- Cursor: use flat names with an `openspec-` prefix: `/openspec-proposal`, `/openspec-apply`, `/openspec-archive`. Group via `category: OpenSpec` when supported.
54+
- Consistency: align file names, visible slash names, and any frontmatter `id` (e.g., `id: openspec-apply`).
55+
- Migration: do not rename existing commands during `update`; apply new naming only on `init` (or via an explicit migrate step).
56+
57+
## Open Questions
58+
- Validate exact metadata/frontmatter supported by each tool version; if unsupported, omit frontmatter and ship Markdown body only.
59+
- Confirm the final Cursor command file location for the targeted versions; fall back to Markdown-only if Cursor does not parse frontmatter.
60+
- Evaluate additional commands beyond the initial three (e.g., `/show-change`, `/validate-all`) based on user demand.
61+
62+
## Alternatives
63+
- Hard-code slash command text per tool (rejected: duplicates content; increases maintenance).
64+
- Delay Cursor support until its config stabilizes (partial accept): gate Cursor behind a feature flag until verified in real environments.
65+
66+
## Risks
67+
- Tool configuration formats may change, requiring updates to wrappers/frontmatter.
68+
- Incorrect paths or categories can hide commands; add path existence checks and clear logging.
69+
- Marker misuse (inside frontmatter) can break parsing; enforce placement rules in tests.
70+
71+
## Future Work
72+
- Support additional editors/agents that expose slash command APIs.
73+
- Allow users to customize command names and categories during `openspec init`.
74+
- Provide a dedicated command to regenerate slash commands without running full `update`.
75+
76+
## File Format Examples
77+
The following examples illustrate expected structure. If a tool does not support frontmatter, omit the YAML block and keep only the markers + body.
78+
79+
### Claude Code: `.claude/commands/openspec/proposal.md`
80+
```markdown
81+
---
82+
name: OpenSpec: Proposal
83+
description: Scaffold a new OpenSpec change and validate strictly.
84+
category: OpenSpec
85+
tags: [openspec, change]
86+
---
87+
<!-- OPENSPEC:START -->
88+
...command body from shared template...
89+
<!-- OPENSPEC:END -->
90+
```
91+
92+
Slash invocation: `/openspec/proposal` (namespaced)
93+
94+
### Cursor: `.cursor/commands/openspec-proposal.md`
95+
```markdown
96+
---
97+
name: /openspec-proposal
98+
id: openspec-proposal
99+
category: OpenSpec
100+
description: Scaffold a new OpenSpec change and validate strictly.
101+
---
102+
<!-- OPENSPEC:START -->
103+
...command body from shared template...
104+
<!-- OPENSPEC:END -->
105+
```
106+
107+
Slash invocation: `/openspec-proposal` (flat, prefixed)
108+
109+
## Template Content
110+
Templates should be brief, actionable, and sourced from `openspec/README.md` to avoid duplication. Each command body includes:
111+
- Guardrails: ask 1–2 clarifying questions if needed; follow minimal-complexity rules; use `pnpm` for Node projects.
112+
- Step list tailored to the workflow stage (proposal, apply, archive), including strict validation commands.
113+
- Pointers to `openspec show`, `openspec list`, and troubleshooting tips when validation fails.
114+
115+
## Testing Strategy
116+
- Golden snapshots for generated files per tool (frontmatter + markers + body).
117+
- Partial presence tests: if 1–2 files exist, `update` only refreshes those and does not create missing ones.
118+
- Marker placement tests: ensure markers never appear inside frontmatter; cover missing/duplicated marker recovery behavior.
119+
- Logging tests: `update` reports per-file updates for slash commands.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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: Missing slash command file
16+
- **WHEN** a tool lacks a slash command file
17+
- **THEN** do not create a new file during update
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Implementation Tasks
2+
3+
## 1. Templates and Configurators
4+
- [ ] 1.1 Create shared templates for the Proposal, Apply, and Archive commands with instructions for each workflow stage from `openspec/README.md`.
5+
- [ ] 1.2 Implement a `SlashCommandConfigurator` base and tool-specific configurators for Claude Code and Cursor.
6+
7+
## 2. Claude Code Integration
8+
- [ ] 2.1 Generate `.claude/commands/openspec/{proposal,apply,archive}.md` during `openspec init` using shared templates.
9+
- [ ] 2.2 Update existing `.claude/commands/openspec/*` files during `openspec update`.
10+
11+
## 3. Cursor Integration
12+
- [ ] 3.1 Generate `.cursor/commands/{openspec-proposal,openspec-apply,openspec-archive}.md` during `openspec init` using shared templates.
13+
- [ ] 3.2 Update existing `.cursor/commands/*` files during `openspec update`.
14+
15+
## 4. Verification
16+
- [ ] 4.1 Add tests verifying slash command files are created and updated correctly.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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/<capability>/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+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+

src/core/templates/readme-template.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,19 @@ Every requirement MUST have at least one scenario.
256256
257257
Headers matched with \`trim(header)\` - whitespace ignored.
258258
259+
#### When to use ADDED vs MODIFIED
260+
- ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding "Slash Command Configuration") rather than altering the semantics of an existing requirement.
261+
- MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.
262+
- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.
263+
264+
Common pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you aren’t explicitly changing the existing requirement, add a new requirement under ADDED instead.
265+
266+
Authoring a MODIFIED requirement correctly:
267+
1) Locate the existing requirement in \`openspec/specs/<capability>/spec.md\`.
268+
2) Copy the entire requirement block (from \`### Requirement: ...\` through its scenarios).
269+
3) Paste it under \`## MODIFIED Requirements\` and edit to reflect the new behavior.
270+
4) Ensure the header text matches exactly (whitespace-insensitive) and keep at least one \`#### Scenario:\`.
271+
259272
Example for RENAMED:
260273
\`\`\`markdown
261274
## RENAMED Requirements

0 commit comments

Comments
 (0)