mirror of
https://github.com/Fission-AI/OpenSpec.git
synced 2026-10-04 06:18:24 +08:00
Compare commits
89
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
835c15a2f6 | ||
|
|
847aa81c0f | ||
|
|
39bebefcc4 | ||
|
|
cf8b6212c8 | ||
|
|
c157483685 | ||
|
|
f90c7c3354 | ||
|
|
9381bd3b24 | ||
|
|
ae83b4e16d | ||
|
|
d48528134b | ||
|
|
54bd3f1ccd | ||
|
|
675e870bf1 | ||
|
|
07eaf7b691 | ||
|
|
153721d14a | ||
|
|
70c2e17525 | ||
|
|
e2c333e493 | ||
|
|
e137dd3981 | ||
|
|
2beb8e77e8 | ||
|
|
3b16b13613 | ||
|
|
c4cfdc7c49 | ||
|
|
e0736807b4 | ||
|
|
fdb05a723e | ||
|
|
8332a09811 | ||
|
|
d61a49f6d5 | ||
|
|
7d1237f00d | ||
|
|
33466b1e2a | ||
|
|
6c8c778043 | ||
|
|
43b01ad374 | ||
|
|
3cdcdfca8e | ||
|
|
32fc19a60d | ||
|
|
84f372517f | ||
|
|
adda63e17a | ||
|
|
90d05b7115 | ||
|
|
20714c1c28 | ||
|
|
2e51ae26d3 | ||
|
|
dbd4ed7bfb | ||
|
|
473093f885 | ||
|
|
b5a884748b | ||
|
|
690c75225c | ||
|
|
dd53fb7736 | ||
|
|
2a441c472d | ||
|
|
ed4d965208 | ||
|
|
c86985d6ec | ||
|
|
bf4bc2426f | ||
|
|
c57e421cc2 | ||
|
|
ed2e832066 | ||
|
|
9db74aa5ac | ||
|
|
b5b7248610 | ||
|
|
322bfd455a | ||
|
|
08c349369a | ||
|
|
40afee643e | ||
|
|
05023dab43 | ||
|
|
d7a928b4e9 | ||
|
|
07dd634986 | ||
|
|
36078b1947 | ||
|
|
d0e1b076c2 | ||
|
|
2fbda520de | ||
|
|
5633556b6d | ||
|
|
2bb0ed36c5 | ||
|
|
06097f9cb7 | ||
|
|
8f5a526396 | ||
|
|
eb152eb2ca | ||
|
|
e987a5a327 | ||
|
|
4971cda812 | ||
|
|
4715138927 | ||
|
|
940898c1c5 | ||
|
|
d49a88c3bb | ||
|
|
bb9f6ce0ea | ||
|
|
ae85a7229d | ||
|
|
504c93bdf1 | ||
|
|
c4a54a8d54 | ||
|
|
38d2356836 | ||
|
|
3f67debf65 | ||
|
|
533cb0fa87 | ||
|
|
8dfd824477 | ||
|
|
3ed1270316 | ||
|
|
eb15cdb983 | ||
|
|
cd172a4427 | ||
|
|
b7f5a429de | ||
|
|
a5c10ed5e7 | ||
|
|
1bc849554c | ||
|
|
d73705736f | ||
|
|
ed924ffcff | ||
|
|
1786684af6 | ||
|
|
51fb10db5e | ||
|
|
cac54042ce | ||
|
|
c47cdaafe2 | ||
|
|
ea5aa0e562 | ||
|
|
48b5ed9657 | ||
|
|
fb7ff527a6 |
+93
-4
@@ -1,6 +1,95 @@
|
||||
This directory is managed by Changesets.
|
||||
# Changesets
|
||||
|
||||
- Add a changeset locally with `pnpm changeset`.
|
||||
- The CI "Release (prepare)" workflow opens/updates a Version Packages PR.
|
||||
- Publishing happens from a GitHub Release via the "Publish to npm" workflow.
|
||||
This directory is managed by [Changesets](https://github.com/changesets/changesets).
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
pnpm changeset
|
||||
```
|
||||
|
||||
Follow the prompts to select version bump type and describe your changes.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Add a changeset** — Run `pnpm changeset` locally before or after your PR
|
||||
2. **Version PR** — CI opens/updates a "Version Packages" PR when changesets merge to main
|
||||
3. **Release** — Merging the Version PR triggers npm publish and GitHub Release
|
||||
|
||||
> **Note:** Contributors only need to run `pnpm changeset`. Versioning (`changeset version`) and publishing happen automatically in CI.
|
||||
|
||||
## Template
|
||||
|
||||
Use this structure for your changeset content:
|
||||
|
||||
```markdown
|
||||
---
|
||||
"@fission-ai/openspec": patch
|
||||
---
|
||||
|
||||
### New Features
|
||||
|
||||
- **Feature name** — What users can now do
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed issue where X happened when Y
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- `oldMethod()` has been removed, use `newMethod()` instead
|
||||
|
||||
### Deprecations
|
||||
|
||||
- `legacyOption` is deprecated and will be removed in v2.0
|
||||
|
||||
### Other
|
||||
|
||||
- Internal refactoring of X for better performance
|
||||
```
|
||||
|
||||
Include only the sections relevant to your change.
|
||||
|
||||
## Version Bump Guide
|
||||
|
||||
| Type | When to use | Example |
|
||||
|------|-------------|---------|
|
||||
| `patch` | Bug fixes, small improvements | Fixed crash when config missing |
|
||||
| `minor` | New features, non-breaking additions | Added `--verbose` flag |
|
||||
| `major` | Breaking changes, removed features | Renamed `init` to `setup` |
|
||||
|
||||
## When to Create a Changeset
|
||||
|
||||
**Create one for:**
|
||||
- New features or commands
|
||||
- Bug fixes that affect users
|
||||
- Breaking changes or deprecations
|
||||
- Performance improvements users would notice
|
||||
|
||||
**Skip for:**
|
||||
- Documentation-only changes
|
||||
- Test additions/fixes
|
||||
- Internal refactoring with no user impact
|
||||
- CI/tooling changes
|
||||
|
||||
## Writing Good Descriptions
|
||||
|
||||
**Do:** Write for users, not developers
|
||||
```markdown
|
||||
- **Shell completions** — Tab completion now available for Bash, Fish, and PowerShell
|
||||
```
|
||||
|
||||
**Don't:** Write implementation details
|
||||
```markdown
|
||||
- Added ShellCompletionGenerator class with Bash/Fish/PowerShell subclasses
|
||||
```
|
||||
|
||||
**Do:** Explain the impact
|
||||
```markdown
|
||||
- Fixed config loading to respect `XDG_CONFIG_HOME` on Linux
|
||||
```
|
||||
|
||||
**Don't:** Just reference the fix
|
||||
```markdown
|
||||
- Fixed #123
|
||||
```
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config/schema.json",
|
||||
"changelog": "@changesets/cli/changelog",
|
||||
"changelog": [
|
||||
"@changesets/changelog-github",
|
||||
{ "repo": "Fission-AI/OpenSpec" }
|
||||
],
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"linked": [],
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Github Workflows
|
||||
|
||||
## Testing CI Locally
|
||||
|
||||
Test GitHub Actions workflows locally using [act](https://nektosact.com/):
|
||||
|
||||
```bash
|
||||
# Test all PR checks
|
||||
act pull_request
|
||||
|
||||
# Test specific job
|
||||
act pull_request -j nix-flake-validate
|
||||
|
||||
# Dry run to see what would execute
|
||||
act pull_request --dryrun
|
||||
```
|
||||
|
||||
The `.actrc` file configures act to use the appropriate Docker image.
|
||||
|
||||
|
||||
+101
-2
@@ -15,6 +15,29 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Detect which files changed to enable path-based filtering
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
nix: ${{ steps.filter.outputs.nix }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check for Nix-related changes
|
||||
uses: dorny/paths-filter@v3
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
nix:
|
||||
- 'flake.nix'
|
||||
- 'flake.lock'
|
||||
- 'package.json'
|
||||
- 'pnpm-lock.yaml'
|
||||
- 'scripts/update-flake.sh'
|
||||
- '.github/workflows/ci.yml'
|
||||
|
||||
test_pr:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
@@ -156,6 +179,66 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
nix-flake-validate:
|
||||
name: Nix Flake Validation
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
needs: changes
|
||||
if: needs.changes.outputs.nix == 'true'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@v13
|
||||
|
||||
- name: Setup Nix cache
|
||||
uses: DeterminateSystems/magic-nix-cache-action@v8
|
||||
|
||||
- name: Build with Nix
|
||||
run: nix build
|
||||
|
||||
- name: Verify build output
|
||||
run: |
|
||||
if [ ! -e "result" ]; then
|
||||
echo "Error: Nix build output 'result' symlink not found"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "result/bin/openspec" ]; then
|
||||
echo "Error: openspec binary not found in build output"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Build output verified"
|
||||
|
||||
- name: Test binary execution
|
||||
run: |
|
||||
VERSION=$(nix run . -- --version)
|
||||
echo "OpenSpec version: $VERSION"
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Error: Version command returned empty output"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Binary execution successful"
|
||||
|
||||
- name: Validate update script
|
||||
run: |
|
||||
echo "Testing update-flake.sh script..."
|
||||
bash scripts/update-flake.sh
|
||||
echo "✅ Update script executed successfully"
|
||||
|
||||
- name: Check flake.nix modifications
|
||||
run: |
|
||||
if git diff --quiet flake.nix; then
|
||||
echo "⚠️ Warning: flake.nix was not modified by update script"
|
||||
else
|
||||
echo "✅ flake.nix was updated by script"
|
||||
git diff flake.nix
|
||||
fi
|
||||
|
||||
- name: Restore flake.nix
|
||||
if: always()
|
||||
run: git checkout -- flake.nix || true
|
||||
|
||||
validate-changesets:
|
||||
name: Validate Changesets
|
||||
runs-on: ubuntu-latest
|
||||
@@ -191,7 +274,7 @@ jobs:
|
||||
required-checks-pr:
|
||||
name: All checks passed
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test_pr, lint]
|
||||
needs: [test_pr, lint, nix-flake-validate]
|
||||
if: always() && github.event_name == 'pull_request'
|
||||
steps:
|
||||
- name: Verify all checks passed
|
||||
@@ -204,12 +287,20 @@ jobs:
|
||||
echo "Lint job failed"
|
||||
exit 1
|
||||
fi
|
||||
# Nix validation may be skipped if no Nix-related files changed
|
||||
if [[ "${{ needs.nix-flake-validate.result }}" != "success" && "${{ needs.nix-flake-validate.result }}" != "skipped" ]]; then
|
||||
echo "Nix flake validation job failed"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${{ needs.nix-flake-validate.result }}" == "skipped" ]]; then
|
||||
echo "Nix flake validation skipped (no Nix-related changes)"
|
||||
fi
|
||||
echo "All required checks passed!"
|
||||
|
||||
required-checks-main:
|
||||
name: All checks passed
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test_matrix, lint]
|
||||
needs: [test_matrix, lint, nix-flake-validate]
|
||||
if: always() && github.event_name != 'pull_request'
|
||||
steps:
|
||||
- name: Verify all checks passed
|
||||
@@ -222,4 +313,12 @@ jobs:
|
||||
echo "Lint job failed"
|
||||
exit 1
|
||||
fi
|
||||
# Nix validation may be skipped if no Nix-related files changed
|
||||
if [[ "${{ needs.nix-flake-validate.result }}" != "success" && "${{ needs.nix-flake-validate.result }}" != "skipped" ]]; then
|
||||
echo "Nix flake validation job failed"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${{ needs.nix-flake-validate.result }}" == "skipped" ]]; then
|
||||
echo "Nix flake validation skipped (no Nix-related changes)"
|
||||
fi
|
||||
echo "All required checks passed!"
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
name: Polish Release Notes
|
||||
|
||||
# Uses Claude to transform raw changelog into polished release notes.
|
||||
# Triggered automatically by release-prepare after publishing, or manually.
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [polish-release-notes]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: 'Release tag to polish (e.g., v0.18.0)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
env:
|
||||
# repository_dispatch passes tag via client_payload, workflow_dispatch via inputs
|
||||
TAG_NAME: ${{ github.event.client_payload.tag_name || inputs.tag_name }}
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
polish:
|
||||
# Only run on the main repo, not forks
|
||||
if: github.repository == 'Fission-AI/OpenSpec'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Get current release body
|
||||
id: get-release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh release view "${{ env.TAG_NAME }}" --json body -q '.body' > current-notes.md
|
||||
echo "Fetched release notes for ${{ env.TAG_NAME }}"
|
||||
|
||||
- name: Transform release notes with Claude
|
||||
uses: anthropics/claude-code-action@v1
|
||||
id: claude
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
claude_args: "--allowedTools Write,Read"
|
||||
prompt: |
|
||||
Transform the changelog in `current-notes.md` into release notes for OpenSpec ${{ env.TAG_NAME }}.
|
||||
|
||||
## Voice
|
||||
|
||||
OpenSpec is a developer tool. Write like you're talking to a peer:
|
||||
- Direct and practical, not marketing copy
|
||||
- Focus on what changed and why it matters
|
||||
- Skip the hype, keep it real
|
||||
|
||||
## Output
|
||||
|
||||
Create two files:
|
||||
|
||||
### 1. `release-title.txt`
|
||||
|
||||
A short title in this format:
|
||||
```
|
||||
${{ env.TAG_NAME }} - [1-4 words describing the release]
|
||||
```
|
||||
|
||||
Examples:
|
||||
- `v0.18.0 - OPSX Experimental Workflow`
|
||||
- `v0.16.0 - Antigravity, iFlow Support`
|
||||
- `v0.15.0 - Gemini CLI, RooCode`
|
||||
|
||||
Rules for title:
|
||||
- Lead with the most notable addition
|
||||
- 1-4 words after the dash, no fluff
|
||||
- If multiple features, comma-separate the top 2
|
||||
- For bugfix-only releases, use something like `v0.17.2 - Pre-commit Hook Fix`
|
||||
|
||||
### 2. `polished-notes.md`
|
||||
|
||||
```markdown
|
||||
## What's New in ${{ env.TAG_NAME }}
|
||||
|
||||
[One sentence: what's the theme of this release?]
|
||||
|
||||
### New
|
||||
|
||||
- **Feature name** - What it does and why you'd use it
|
||||
|
||||
### Improved
|
||||
|
||||
- **Area** - What got better
|
||||
|
||||
### Fixed
|
||||
|
||||
- What was broken, now works
|
||||
```
|
||||
|
||||
Omit empty sections.
|
||||
|
||||
## Rules
|
||||
|
||||
1. Write for developers using OpenSpec with AI coding assistants
|
||||
2. Remove commit hashes (like `eb152eb:`), PR numbers, and changesets wrappers (`### Minor Changes`)
|
||||
3. Lead with what users can do, not implementation details
|
||||
4. One to two sentences per item, max
|
||||
5. Use **bold** for feature/area names
|
||||
6. Skip internal changes (CI, refactors, tests) unless they affect users
|
||||
7. If the input is already well-formatted, just clean up structure and remove noise
|
||||
|
||||
## Example
|
||||
|
||||
Before:
|
||||
```
|
||||
### Minor Changes
|
||||
- 8dfd824: Add OPSX experimental workflow commands and enhanced artifact system
|
||||
**New Commands:**
|
||||
- `/opsx:ff` - Fast-forward through artifact creation
|
||||
```
|
||||
|
||||
After (polished-notes.md):
|
||||
```
|
||||
### New
|
||||
|
||||
- **Fast-forward mode** - Generate all planning artifacts at once with `/opsx:ff`. Useful when you already know what you're building.
|
||||
```
|
||||
|
||||
After (release-title.txt):
|
||||
```
|
||||
v0.18.0 - OPSX Experimental Workflow
|
||||
```
|
||||
|
||||
Write both files. No other output.
|
||||
|
||||
- name: Update release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
TAG="${{ env.TAG_NAME }}"
|
||||
|
||||
if [ -f "polished-notes.md" ] && [ -f "release-title.txt" ]; then
|
||||
TITLE=$(cat release-title.txt)
|
||||
gh release edit "$TAG" --title "$TITLE" --notes-file polished-notes.md
|
||||
echo "Updated: $TITLE"
|
||||
elif [ -f "polished-notes.md" ]; then
|
||||
gh release edit "$TAG" --notes-file polished-notes.md
|
||||
echo "Updated notes (title unchanged)"
|
||||
else
|
||||
echo "No changes generated, keeping original"
|
||||
fi
|
||||
@@ -18,9 +18,20 @@ jobs:
|
||||
if: github.repository == 'Fission-AI/OpenSpec'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Generate GitHub App token first - used for checkout and changesets
|
||||
# This allows git operations to trigger CI workflows on the version PR
|
||||
# (GITHUB_TOKEN cannot trigger workflows by design)
|
||||
- name: Generate GitHub App Token
|
||||
id: app-token
|
||||
uses: actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: ${{ vars.APP_ID }}
|
||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
@@ -36,6 +47,7 @@ jobs:
|
||||
|
||||
# Opens/updates the Version Packages PR; publishes when the Version PR merges
|
||||
- name: Create/Update Version PR
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
title: 'chore(release): version packages'
|
||||
@@ -44,5 +56,21 @@ jobs:
|
||||
# so package.json already contains the bumped version.
|
||||
publish: pnpm run release:ci
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
# npm authentication handled via OIDC trusted publishing (no token needed)
|
||||
|
||||
# Trigger release notes polishing after a release is published
|
||||
# Uses repository_dispatch instead of workflow_dispatch because:
|
||||
# - workflow_dispatch requires actions:write permission (GitHub App doesn't have it)
|
||||
# - repository_dispatch works with contents:write (which we already have)
|
||||
- name: Polish release notes
|
||||
if: steps.changesets.outputs.published == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: |
|
||||
# Get version from package.json (just bumped by changesets)
|
||||
TAG="v$(jq -r .version package.json)"
|
||||
echo "Triggering polish workflow for $TAG"
|
||||
gh api repos/${{ github.repository }}/dispatches \
|
||||
--method POST \
|
||||
--input - <<< "{\"event_type\":\"polish-release-notes\",\"client_payload\":{\"tag_name\":\"$TAG\"}}"
|
||||
|
||||
@@ -148,3 +148,4 @@ CLAUDE.md
|
||||
|
||||
# Pnpm
|
||||
.pnpm-store/
|
||||
result
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
<!-- OPENSPEC:START -->
|
||||
# OpenSpec Instructions
|
||||
|
||||
These instructions are for AI assistants working in this project.
|
||||
|
||||
Always open `@/openspec/AGENTS.md` when the request:
|
||||
- Mentions planning or proposals (words like proposal, spec, change, plan)
|
||||
- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
|
||||
- Sounds ambiguous and you need the authoritative spec before coding
|
||||
|
||||
Use `@/openspec/AGENTS.md` to learn:
|
||||
- How to create and apply change proposals
|
||||
- Spec format and conventions
|
||||
- Project structure and guidelines
|
||||
|
||||
Keep this managed block so 'openspec update' can refresh the instructions.
|
||||
|
||||
<!-- OPENSPEC:END -->
|
||||
|
||||
+124
-3
@@ -1,5 +1,122 @@
|
||||
# @fission-ai/openspec
|
||||
|
||||
## 0.23.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#540](https://github.com/Fission-AI/OpenSpec/pull/540) [`c4cfdc7`](https://github.com/Fission-AI/OpenSpec/commit/c4cfdc7c499daef30d8a218f5f59b8d9e5adb754) Thanks [@TabishB](https://github.com/TabishB)! - ### New Features
|
||||
|
||||
- **Bulk archive skill** — Archive multiple completed changes in a single operation with `/opsx:bulk-archive`. Includes batch validation, spec conflict detection, and consolidated confirmation
|
||||
|
||||
### Other
|
||||
|
||||
- **Simplified setup** — Config creation now uses sensible defaults with helpful comments instead of interactive prompts
|
||||
|
||||
## 0.22.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#530](https://github.com/Fission-AI/OpenSpec/pull/530) [`33466b1`](https://github.com/Fission-AI/OpenSpec/commit/33466b1e2a6798bdd6d0e19149173585b0612e6f) Thanks [@TabishB](https://github.com/TabishB)! - Add project-level configuration, project-local schemas, and schema management commands
|
||||
|
||||
**New Features**
|
||||
|
||||
- **Project-level configuration** — Configure OpenSpec behavior per-project via `openspec/config.yaml`, including custom rules injection, context files, and schema resolution settings
|
||||
- **Project-local schemas** — Define custom artifact schemas within your project's `openspec/schemas/` directory for project-specific workflows
|
||||
- **Schema management commands** — New `openspec schema` commands (`list`, `show`, `export`, `validate`) for inspecting and managing artifact schemas (experimental)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Fixed config loading to handle null `rules` field in project configuration
|
||||
|
||||
## 0.21.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#516](https://github.com/Fission-AI/OpenSpec/pull/516) [`b5a8847`](https://github.com/Fission-AI/OpenSpec/commit/b5a884748be6156a7bb140b4941cfec4f20a9fc8) Thanks [@TabishB](https://github.com/TabishB)! - Add feedback command and Nix flake support
|
||||
|
||||
**New Features**
|
||||
|
||||
- **Feedback command** — Submit feedback directly from the CLI with `openspec feedback`, which creates GitHub Issues with automatic metadata inclusion and graceful fallback for manual submission
|
||||
- **Nix flake support** — Install and develop openspec using Nix with the new `flake.nix`, including automated flake maintenance and CI validation
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- **Explore mode guardrails** — Explore mode now explicitly prevents implementation, keeping the focus on thinking and discovery while still allowing artifact creation
|
||||
|
||||
**Other**
|
||||
|
||||
- Improved change inference in `opsx apply` — automatically detects the target change from conversation context or prompts when ambiguous
|
||||
- Streamlined archive sync assessment with clearer delta spec location guidance
|
||||
|
||||
## 0.20.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#502](https://github.com/Fission-AI/OpenSpec/pull/502) [`9db74aa`](https://github.com/Fission-AI/OpenSpec/commit/9db74aa5ac6547efadaed795217cfa17444f2004) Thanks [@TabishB](https://github.com/TabishB)! - Add `/opsx:verify` command and fix vitest process storms
|
||||
|
||||
**New Features**
|
||||
|
||||
- **`/opsx:verify` command** — Validate that change implementations match their specifications
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Fixed vitest process storms by capping worker parallelism
|
||||
- Fixed agent workflows to use non-interactive mode for validation commands
|
||||
- Fixed PowerShell completions generator to remove trailing commas
|
||||
|
||||
## 0.19.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- eb152eb: Add Continue IDE support, shell completions, and `/opsx:explore` command
|
||||
|
||||
**New Features**
|
||||
|
||||
- **Continue IDE support** – OpenSpec now generates slash commands for [Continue](https://continue.dev/), expanding editor integration options alongside Cursor, Windsurf, Claude Code, and others
|
||||
- **Shell completions for Bash, Fish, and PowerShell** – Run `openspec completion install` to set up tab completion in your preferred shell
|
||||
- **`/opsx:explore` command** – A new thinking partner mode for exploring ideas and investigating problems before committing to changes
|
||||
- **Codebuddy slash command improvements** – Updated frontmatter format for better compatibility
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Shell completions now correctly offer parent-level flags (like `--help`) when a command has subcommands
|
||||
- Fixed Windows compatibility issues in tests
|
||||
|
||||
**Other**
|
||||
|
||||
- Added optional anonymous usage statistics to help understand how OpenSpec is used. This is **opt-out** by default – set `OPENSPEC_TELEMETRY=0` or `DO_NOT_TRACK=1` to disable. Only command names and version are collected; no arguments, file paths, or content. Automatically disabled in CI environments.
|
||||
|
||||
## 0.18.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 8dfd824: Add OPSX experimental workflow commands and enhanced artifact system
|
||||
|
||||
**New Commands:**
|
||||
|
||||
- `/opsx:ff` - Fast-forward through artifact creation, generating all needed artifacts in one go
|
||||
- `/opsx:sync` - Sync delta specs from a change to main specs
|
||||
- `/opsx:archive` - Archive completed changes with smart sync check
|
||||
|
||||
**Artifact Workflow Enhancements:**
|
||||
|
||||
- Schema-aware apply instructions with inline guidance and XML output
|
||||
- Agent schema selection for experimental artifact workflow
|
||||
- Per-change schema metadata via `.openspec.yaml` files
|
||||
- Agent Skills for experimental artifact workflow
|
||||
- Instruction loader for template loading and change context
|
||||
- Restructured schemas as directories with templates
|
||||
|
||||
**Improvements:**
|
||||
|
||||
- Enhanced list command with last modified timestamps and sorting
|
||||
- Change creation utilities for better workflow support
|
||||
|
||||
**Fixes:**
|
||||
|
||||
- Normalize paths for cross-platform glob compatibility
|
||||
- Allow REMOVED requirements when creating new spec files
|
||||
|
||||
## 0.17.2
|
||||
|
||||
### Patch Changes
|
||||
@@ -20,13 +137,15 @@
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 2e71835: ### New Features
|
||||
- 2e71835: Add `openspec config` command and Oh-my-zsh completions
|
||||
|
||||
**New Features**
|
||||
|
||||
- Add `openspec config` command for managing global configuration settings
|
||||
- Implement global config directory with XDG Base Directory specification support
|
||||
- Add Oh-my-zsh shell completions support for enhanced CLI experience
|
||||
|
||||
### Bug Fixes
|
||||
**Bug Fixes**
|
||||
|
||||
- Fix hang in pre-commit hooks by using dynamic imports
|
||||
- Respect XDG_CONFIG_HOME environment variable on all platforms
|
||||
@@ -34,7 +153,7 @@
|
||||
- Align cli-completion spec with implementation
|
||||
- Remove hardcoded agent field from slash commands
|
||||
|
||||
### Documentation
|
||||
**Documentation**
|
||||
|
||||
- Alphabetize AI tools list in README and make it collapsible
|
||||
|
||||
@@ -55,6 +174,8 @@
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add Continue slash command support so `openspec init` can generate `.continue/prompts/openspec-*.prompt` files with MARKDOWN frontmatter and `$ARGUMENTS` placeholder, and refresh them on `openspec update`.
|
||||
|
||||
- Add Antigravity slash command support so `openspec init` can generate `.agent/workflows/openspec-*.md` files with description-only frontmatter and `openspec update` refreshes existing workflows alongside Windsurf.
|
||||
|
||||
## 0.15.0
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Maintainers
|
||||
|
||||
People who maintain and guide OpenSpec.
|
||||
|
||||
## Core Maintainers
|
||||
|
||||
| Name | GitHub | Role |
|
||||
|------|--------|------|
|
||||
| Tabish Bidiwale | [@TabishB](https://github.com/TabishB) | Lead maintainer |
|
||||
|
||||
## Advisors
|
||||
|
||||
Advisors help shape technical direction and provide guidance to the project.
|
||||
|
||||
| Name | GitHub | Focus |
|
||||
|------|--------|-------|
|
||||
| Hari Krishnan | [@harikrishnan83](https://github.com/harikrishnan83) | Technical direction |
|
||||
@@ -26,6 +26,10 @@
|
||||
Follow <a href="https://x.com/0xTab">@0xTab on X</a> for updates · Join the <a href="https://discord.gg/YctCnvvshC">OpenSpec Discord</a> for help and questions.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<sub>🧪 <strong>OPSX Workflow</strong> — schema-driven, hackable, fluid. See <a href="docs/experimental-workflow.md">workflow docs</a> for details.</sub>
|
||||
</p>
|
||||
|
||||
# OpenSpec
|
||||
|
||||
OpenSpec aligns humans and AI coding assistants with spec-driven development so you agree on what to build before any code is written. **No API keys required.**
|
||||
@@ -85,42 +89,26 @@ See the full comparison in [How OpenSpec Compares](#how-openspec-compares).
|
||||
|
||||
### Supported AI Tools
|
||||
|
||||
OpenSpec generates **Agent Skills** and **/opsx:\* slash commands** for supported tools during `openspec init`.
|
||||
|
||||
<details>
|
||||
<summary><strong>Native Slash Commands</strong> (click to expand)</summary>
|
||||
<summary><strong>Tools with Agent Skills + Slash Commands</strong> (click to expand)</summary>
|
||||
|
||||
These tools have built-in OpenSpec commands. Select the OpenSpec integration when prompted.
|
||||
These tools support the full OpenSpec workflow with skills and commands:
|
||||
|
||||
| Tool | Commands |
|
||||
|------|----------|
|
||||
| **Amazon Q Developer** | `@openspec-proposal`, `@openspec-apply`, `@openspec-archive` (`.amazonq/prompts/`) |
|
||||
| **Antigravity** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.agent/workflows/`) |
|
||||
| **Auggie (Augment CLI)** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.augment/commands/`) |
|
||||
| **Claude Code** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` |
|
||||
| **Cline** | Workflows in `.clinerules/workflows/` directory (`.clinerules/workflows/openspec-*.md`) |
|
||||
| **CodeBuddy Code (CLI)** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.codebuddy/commands/`) — see [docs](https://www.codebuddy.ai/cli) |
|
||||
| **Codex** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (global: `~/.codex/prompts`, auto-installed) |
|
||||
| **CoStrict** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.cospec/openspec/commands/`) — see [docs](https://costrict.ai)|
|
||||
| **Crush** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.crush/commands/openspec/`) |
|
||||
| **Cursor** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` |
|
||||
| **Factory Droid** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.factory/commands/`) |
|
||||
| **Gemini CLI** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.gemini/commands/openspec/`) |
|
||||
| **GitHub Copilot** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.github/prompts/`) |
|
||||
| **iFlow (iflow-cli)** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.iflow/commands/`) |
|
||||
| **Kilo Code** | `/openspec-proposal.md`, `/openspec-apply.md`, `/openspec-archive.md` (`.kilocode/workflows/`) |
|
||||
| **OpenCode** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` |
|
||||
| **Qoder (CLI)** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.qoder/commands/openspec/`) — see [docs](https://qoder.com/cli) |
|
||||
| **Qwen Code** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.qwen/commands/`) |
|
||||
| **RooCode** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.roo/commands/`) |
|
||||
| **Windsurf** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.windsurf/workflows/`) |
|
||||
| Tool | Skills Location | Commands |
|
||||
|------|-----------------|----------|
|
||||
| **Claude Code** | `.claude/skills/` | `/opsx:new`, `/opsx:apply`, `/opsx:archive`, etc. |
|
||||
| **Cursor** | `.cursor/skills/` | `/opsx:*` commands via prompts |
|
||||
|
||||
Kilo Code discovers team workflows automatically. Save the generated files under `.kilocode/workflows/` and trigger them from the command palette with `/openspec-proposal.md`, `/openspec-apply.md`, or `/openspec-archive.md`.
|
||||
Run `openspec init` and select the tools you use. Skills and commands are generated automatically.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>AGENTS.md Compatible</strong> (click to expand)</summary>
|
||||
|
||||
These tools automatically read workflow instructions from `openspec/AGENTS.md`. Ask them to follow the OpenSpec workflow if they need a reminder. Learn more about the [AGENTS.md convention](https://agents.md/).
|
||||
Tools that support AGENTS.md can follow OpenSpec workflows by reading `openspec/AGENTS.md`. Ask them to follow the OpenSpec workflow if they need a reminder. Learn more about the [AGENTS.md convention](https://agents.md/).
|
||||
|
||||
| Tools |
|
||||
|-------|
|
||||
@@ -135,6 +123,8 @@ These tools automatically read workflow instructions from `openspec/AGENTS.md`.
|
||||
|
||||
#### Step 1: Install the CLI globally
|
||||
|
||||
**Option A: Using npm**
|
||||
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
```
|
||||
@@ -144,6 +134,39 @@ Verify installation:
|
||||
openspec --version
|
||||
```
|
||||
|
||||
**Option B: Using Nix (NixOS and Nix package manager)**
|
||||
|
||||
Run OpenSpec directly without installation:
|
||||
```bash
|
||||
nix run github:Fission-AI/OpenSpec -- init
|
||||
```
|
||||
|
||||
Or install to your profile:
|
||||
```bash
|
||||
nix profile install github:Fission-AI/OpenSpec
|
||||
```
|
||||
|
||||
Or add to your development environment in `flake.nix`:
|
||||
```nix
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
openspec.url = "github:Fission-AI/OpenSpec";
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, openspec, ... }: {
|
||||
devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {
|
||||
buildInputs = [ openspec.packages.x86_64-linux.default ];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Verify installation:
|
||||
```bash
|
||||
openspec --version
|
||||
```
|
||||
|
||||
#### Step 2: Initialize OpenSpec in your project
|
||||
|
||||
Navigate to your project directory:
|
||||
@@ -157,102 +180,139 @@ openspec init
|
||||
```
|
||||
|
||||
**What happens during initialization:**
|
||||
- You'll be prompted to pick any natively supported AI tools (Claude Code, CodeBuddy, Cursor, OpenCode, Qoder,etc.); other assistants always rely on the shared `AGENTS.md` stub
|
||||
- OpenSpec automatically configures slash commands for the tools you choose and always writes a managed `AGENTS.md` hand-off at the project root
|
||||
- A new `openspec/` directory structure is created in your project
|
||||
- You'll see an interactive tool selector to pick AI tools (Claude Code, Cursor, etc.)
|
||||
- OpenSpec generates **Agent Skills** in tool-specific directories (e.g., `.claude/skills/`)
|
||||
- **/opsx:\* slash commands** are created for each selected tool
|
||||
- A `openspec/config.yaml` file is created for project configuration
|
||||
- The `openspec/` directory structure is created (specs, changes, archive)
|
||||
|
||||
**After setup:**
|
||||
- Primary AI tools can trigger `/openspec` workflows without additional configuration
|
||||
- Run `openspec list` to verify the setup and view any active changes
|
||||
- If your coding assistant doesn't surface the new slash commands right away, restart it. Slash commands are loaded at startup,
|
||||
so a fresh launch ensures they appear
|
||||
**Legacy upgrade:** If you have files from an older OpenSpec version, init will detect them and offer to clean up automatically. Use `--force` to skip the confirmation prompt.
|
||||
|
||||
### Optional: Populate Project Context
|
||||
|
||||
After `openspec init` completes, you'll receive a suggested prompt to help populate your project context:
|
||||
|
||||
```text
|
||||
Populate your project context:
|
||||
"Please read openspec/project.md and help me fill it out with details about my project, tech stack, and conventions"
|
||||
**Non-interactive mode:** For CI or scripted setups:
|
||||
```bash
|
||||
openspec init --tools claude,cursor # Specific tools
|
||||
openspec init --tools all # All supported tools
|
||||
openspec init --tools none # Skip tool setup
|
||||
```
|
||||
|
||||
Use `openspec/project.md` to define project-level conventions, standards, architectural patterns, and other guidelines that should be followed across all changes.
|
||||
**After setup:**
|
||||
- Run `/opsx:new` to start your first change
|
||||
- Run `openspec list` to verify the setup and view any active changes
|
||||
- Restart your IDE for slash commands to take effect
|
||||
|
||||
### Optional: Configure Project Context
|
||||
|
||||
After `openspec init`, you can customize `openspec/config.yaml` to inject project-specific context into all artifacts:
|
||||
|
||||
```yaml
|
||||
# openspec/config.yaml
|
||||
schema: spec-driven
|
||||
|
||||
context: |
|
||||
Tech stack: TypeScript, React, Node.js
|
||||
Testing: Vitest for unit tests
|
||||
Style: ESLint with Prettier
|
||||
|
||||
rules:
|
||||
proposal:
|
||||
- Include rollback plan
|
||||
specs:
|
||||
- Use Given/When/Then format for scenarios
|
||||
```
|
||||
|
||||
This context is automatically included in artifact instructions, helping the AI understand your project's conventions.
|
||||
|
||||
### Create Your First Change
|
||||
|
||||
Here's a real example showing the complete OpenSpec workflow. This works with any AI tool. Those with native slash commands will recognize the shortcuts automatically.
|
||||
|
||||
#### 1. Draft the Proposal
|
||||
Start by asking your AI to create a change proposal:
|
||||
Here's a real example showing the complete OpenSpec workflow using `/opsx:*` commands.
|
||||
|
||||
#### 1. Start a New Change
|
||||
```text
|
||||
You: Create an OpenSpec change proposal for adding profile search filters by role and team
|
||||
(Shortcut for tools with slash commands: /openspec:proposal Add profile search filters)
|
||||
You: /opsx:new
|
||||
|
||||
AI: I'll create an OpenSpec change proposal for profile filters.
|
||||
*Scaffolds openspec/changes/add-profile-filters/ with proposal.md, tasks.md, spec deltas.*
|
||||
AI: What do you want to build?
|
||||
You: Add profile search filters by role and team
|
||||
|
||||
AI: I'll create a new change for profile filters.
|
||||
*Creates openspec/changes/add-profile-filters/ with proposal.md*
|
||||
```
|
||||
|
||||
#### 2. Verify & Review
|
||||
Check that the change was created correctly and review the proposal:
|
||||
#### 2. Build Out Artifacts
|
||||
Use `/opsx:continue` to create artifacts one at a time, or `/opsx:ff` to fast-forward through all planning artifacts:
|
||||
|
||||
```text
|
||||
You: /opsx:continue
|
||||
|
||||
AI: Proposal is done. Ready to create: specs, design
|
||||
Which artifact should I create?
|
||||
You: specs
|
||||
|
||||
AI: *Creates specs with requirements and scenarios*
|
||||
```
|
||||
|
||||
Or fast-forward through everything:
|
||||
```text
|
||||
You: /opsx:ff add-profile-filters
|
||||
|
||||
AI: *Creates proposal → specs → design → tasks in sequence*
|
||||
```
|
||||
|
||||
#### 3. Verify & Review
|
||||
```bash
|
||||
$ openspec list # Confirm the change folder exists
|
||||
$ openspec validate add-profile-filters # Validate spec formatting
|
||||
$ openspec show add-profile-filters # Review proposal, tasks, and spec delta
|
||||
```
|
||||
|
||||
#### 3. Refine the Specs
|
||||
Iterate on the specifications until they match your needs:
|
||||
|
||||
```text
|
||||
You: Can you add acceptance criteria for the role and team filters?
|
||||
|
||||
AI: I'll update the spec delta with scenarios for role and team filters.
|
||||
*Edits openspec/changes/add-profile-filters/specs/profile/spec.md and tasks.md.*
|
||||
openspec list # Confirm the change folder exists
|
||||
openspec validate add-profile-filters # Validate spec formatting
|
||||
openspec show add-profile-filters # Review proposal, tasks, and spec delta
|
||||
```
|
||||
|
||||
#### 4. Implement the Change
|
||||
Once specs look good, start implementation:
|
||||
|
||||
```text
|
||||
You: The specs look good. Let's implement this change.
|
||||
(Shortcut for tools with slash commands: /openspec:apply add-profile-filters)
|
||||
You: /opsx:apply
|
||||
|
||||
AI: I'll work through the tasks in the add-profile-filters change.
|
||||
*Implements tasks from openspec/changes/add-profile-filters/tasks.md*
|
||||
*Marks tasks complete: Task 1.1 ✓, Task 1.2 ✓, Task 2.1 ✓...*
|
||||
*Implements tasks, marking them complete as it goes*
|
||||
```
|
||||
|
||||
**Key feature:** If you discover issues during implementation, you can update specs, design, or tasks — then continue. No phase gates.
|
||||
|
||||
#### 5. Archive the Completed Change
|
||||
After implementation is complete, archive the change:
|
||||
|
||||
```text
|
||||
AI: All tasks are complete. The implementation is ready.
|
||||
|
||||
You: Please archive the change
|
||||
(Shortcut for tools with slash commands: /openspec:archive add-profile-filters)
|
||||
You: /opsx:archive
|
||||
|
||||
AI: I'll archive the add-profile-filters change.
|
||||
*Runs: openspec archive add-profile-filters --yes*
|
||||
✓ Change archived successfully. Specs updated. Ready for the next feature!
|
||||
*Runs: openspec archive add-profile-filters --yes*
|
||||
✓ Change archived. Specs updated. Ready for the next feature!
|
||||
```
|
||||
|
||||
Or run the command yourself in terminal:
|
||||
Or run directly in terminal:
|
||||
```bash
|
||||
$ openspec archive add-profile-filters --yes # Archive the completed change without prompts
|
||||
openspec archive add-profile-filters --yes
|
||||
```
|
||||
|
||||
**Note:** Tools with native slash commands (Claude Code, CodeBuddy, Cursor, Codex, Qoder, RooCode) can use the shortcuts shown. All other tools work with natural language requests to "create an OpenSpec proposal", "apply the OpenSpec change", or "archive the change".
|
||||
|
||||
## Command Reference
|
||||
|
||||
### Slash Commands (in your AI tool)
|
||||
|
||||
| Command | What it does |
|
||||
|---------|--------------|
|
||||
| `/opsx:explore` | Think through ideas, investigate problems, clarify requirements |
|
||||
| `/opsx:new` | Start a new change |
|
||||
| `/opsx:continue` | Create the next artifact (based on what's ready) |
|
||||
| `/opsx:ff` | Fast-forward — create all planning artifacts at once |
|
||||
| `/opsx:apply` | Implement tasks, updating artifacts as needed |
|
||||
| `/opsx:sync` | Sync delta specs to main specs |
|
||||
| `/opsx:archive` | Archive when done |
|
||||
| `/opsx:verify` | Verify implementation matches change artifacts |
|
||||
|
||||
### CLI Commands (in terminal)
|
||||
|
||||
```bash
|
||||
openspec init # Initialize OpenSpec with skills and commands
|
||||
openspec list # View active change folders
|
||||
openspec view # Interactive dashboard of specs and changes
|
||||
openspec show <change> # Display change details (proposal, tasks, spec updates)
|
||||
openspec validate <change> # Check spec formatting and structure
|
||||
openspec archive <change> [--yes|-y] # Move a completed change into archive/ (non-interactive with --yes)
|
||||
openspec archive <change> [--yes|-y] # Move a completed change into archive/
|
||||
openspec update # Refresh skills and commands for configured tools
|
||||
```
|
||||
|
||||
## Example: How AI Creates OpenSpec Files
|
||||
@@ -352,12 +412,12 @@ Without specs, AI coding assistants generate code from vague prompts, often miss
|
||||
|
||||
## Team Adoption
|
||||
|
||||
1. **Initialize OpenSpec** – Run `openspec init` in your repo.
|
||||
2. **Start with new features** – Ask your AI to capture upcoming work as change proposals.
|
||||
1. **Initialize OpenSpec** – Run `openspec init` in your repo and select your team's tools.
|
||||
2. **Start with new features** – Use `/opsx:new` to capture upcoming work as change proposals.
|
||||
3. **Grow incrementally** – Each change archives into living specs that document your system.
|
||||
4. **Stay flexible** – Different teammates can use Claude Code, CodeBuddy, Cursor, or any AGENTS.md-compatible tool while sharing the same specs.
|
||||
4. **Stay flexible** – Different teammates can use Claude Code, Cursor, or any AGENTS.md-compatible tool while sharing the same specs.
|
||||
|
||||
Run `openspec update` whenever someone switches tools so your agents pick up the latest instructions and slash-command bindings.
|
||||
Run `openspec update` to refresh skills and commands when upgrading OpenSpec or adding new tools.
|
||||
|
||||
## Updating OpenSpec
|
||||
|
||||
@@ -365,8 +425,51 @@ Run `openspec update` whenever someone switches tools so your agents pick up the
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
```
|
||||
2. **Refresh agent instructions**
|
||||
- Run `openspec update` inside each project to regenerate AI guidance and ensure the latest slash commands are active.
|
||||
2. **Refresh skills and commands**
|
||||
```bash
|
||||
openspec update
|
||||
```
|
||||
This regenerates skills and slash commands for all configured tools.
|
||||
|
||||
3. **Restart your IDE** for slash commands to take effect.
|
||||
|
||||
## Workflow Customization
|
||||
|
||||
<details>
|
||||
<summary><strong>Custom Schemas & Templates</strong></summary>
|
||||
|
||||
OpenSpec uses a **schema-driven workflow** that you can customize:
|
||||
|
||||
**Why customize:**
|
||||
- **Hackable** — edit templates and schemas yourself, test immediately, no rebuild
|
||||
- **Granular** — each artifact has its own instructions, test and tweak individually
|
||||
- **Customizable** — define your own workflows, artifacts, and dependencies
|
||||
|
||||
**Built-in schemas:**
|
||||
- `spec-driven` (default): proposal → specs → design → tasks
|
||||
- `tdd`: tests → implementation → docs
|
||||
|
||||
**Create custom schemas:**
|
||||
```bash
|
||||
openspec schema init my-workflow # Create new schema interactively
|
||||
openspec schema fork spec-driven my-workflow # Fork existing schema
|
||||
openspec schemas # List available schemas
|
||||
```
|
||||
|
||||
Schemas are stored in `openspec/schemas/` (project) or `~/.local/share/openspec/schemas/` (global).
|
||||
|
||||
[Full documentation →](docs/experimental-workflow.md)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Telemetry</strong> – OpenSpec collects anonymous usage stats (opt-out: <code>OPENSPEC_TELEMETRY=0</code>)</summary>
|
||||
|
||||
We collect only command names and version to understand usage patterns. No arguments, paths, content, or PII. Automatically disabled in CI.
|
||||
|
||||
**Opt-out:** `export OPENSPEC_TELEMETRY=0` or `export DO_NOT_TRACK=1`
|
||||
|
||||
</details>
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -376,6 +479,13 @@ Run `openspec update` whenever someone switches tools so your agents pick up the
|
||||
- Develop CLI locally: `pnpm run dev` or `pnpm run dev:cli`
|
||||
- Conventional commits (one-line): `type(scope): subject`
|
||||
|
||||
<details>
|
||||
<summary><strong>Maintainers & Advisors</strong></summary>
|
||||
|
||||
See [MAINTAINERS.md](MAINTAINERS.md) for the list of core maintainers and advisors who help guide the project.
|
||||
|
||||
</details>
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
@@ -0,0 +1,926 @@
|
||||
# OpenSpec Experimental Release Plan
|
||||
|
||||
This document outlines the plan to release the experimental artifact workflow system for user testing.
|
||||
|
||||
## Overview
|
||||
|
||||
The goal is to allow users to test the new artifact-driven workflow system alongside the existing OpenSpec commands. This experimental system (`opsx`) provides a more granular, step-by-step approach to creating change artifacts.
|
||||
|
||||
## Three Workflow Modes
|
||||
|
||||
### 1. Old Workflow (Current Production)
|
||||
- **Commands**: `/openspec:proposal`, `/openspec:apply`, `/openspec:archive`
|
||||
- **Behavior**: Hardcoded slash commands that generate all artifacts in one command
|
||||
- **Status**: Production, unchanged
|
||||
|
||||
### 2. New Artifact System - Batch Mode (Future)
|
||||
- **Commands**: Refactored `/openspec:proposal` using schemas
|
||||
- **Behavior**: Schema-driven but generates all artifacts at once (like legacy)
|
||||
- **Status**: Not in scope for this experimental release
|
||||
- **Note**: This is a future refactor to unify the old system with schemas
|
||||
|
||||
### 3. New Artifact System - Granular Mode (Experimental)
|
||||
- **Commands**: `/opsx:new`, `/opsx:continue`
|
||||
- **Behavior**: One artifact at a time, dependency-driven, iterative
|
||||
- **Status**: Target for this experimental release
|
||||
|
||||
---
|
||||
|
||||
## Work Items
|
||||
|
||||
### 1. Rename AWF to OPSX
|
||||
|
||||
**Current State:**
|
||||
- Commands: `/awf:start`, `/awf:continue`
|
||||
- Files: `.claude/commands/awf/start.md`, `.claude/commands/awf/continue.md`
|
||||
|
||||
**Target State:**
|
||||
- Commands: `/opsx:new`, `/opsx:continue`
|
||||
- Files: `.claude/commands/opsx/new.md`, `.claude/commands/opsx/continue.md`
|
||||
|
||||
**Tasks:**
|
||||
- [x] Create `.claude/commands/opsx/` directory
|
||||
- [x] Rename `start.md` → `new.md` and update content
|
||||
- [x] Copy `continue.md` with updated references
|
||||
- [x] Update all references from "awf" to "opsx" in command content
|
||||
- [x] Update frontmatter (name, description) to use "opsx" naming
|
||||
- [x] Remove `.claude/commands/awf/` directory
|
||||
|
||||
**CLI Commands:**
|
||||
The underlying CLI commands (`openspec status`, `openspec instructions`, etc.) remain unchanged. Only the slash command names change.
|
||||
|
||||
---
|
||||
|
||||
### 2. Remove WF Skill Files
|
||||
|
||||
**Current State:**
|
||||
- `.claude/commands/wf/start.md` - References non-existent `openspec wf` commands
|
||||
- `.claude/commands/wf/continue.md` - References non-existent `openspec wf` commands
|
||||
|
||||
**Target State:**
|
||||
- Directory and files removed
|
||||
|
||||
**Tasks:**
|
||||
- [x] Delete `.claude/commands/wf/start.md`
|
||||
- [x] Delete `.claude/commands/wf/continue.md`
|
||||
- [x] Delete `.claude/commands/wf/` directory
|
||||
|
||||
---
|
||||
|
||||
### 3. Add Agent Skills for Experimental Workflow
|
||||
|
||||
**Purpose:**
|
||||
Generate experimental workflow skills using the [Agent Skills](https://agentskills.io/specification) open standard.
|
||||
|
||||
**Why Skills Instead of Slash Commands:**
|
||||
- **Cross-editor compatibility**: Skills work in Claude Code, Cursor, Windsurf, and other compatible editors automatically
|
||||
- **Simpler implementation**: Single directory (`.claude/skills/`) instead of 18+ editor-specific configurators
|
||||
- **Standard format**: Open standard with simple YAML frontmatter + markdown
|
||||
- **User invocation**: Users explicitly invoke skills when they want to use them
|
||||
|
||||
**Behavior:**
|
||||
1. Create `.claude/skills/` directory if it doesn't exist
|
||||
2. Generate two skills using the Agent Skills specification:
|
||||
- `openspec-new-change/SKILL.md` - Start a new change with artifact workflow
|
||||
- `openspec-continue-change/SKILL.md` - Continue working on a change (create next artifact)
|
||||
3. Skills are added **alongside** existing `/openspec:*` commands (not replacing)
|
||||
|
||||
**Supported Editors:**
|
||||
- Claude Code (native support)
|
||||
- Cursor (native support via Settings → Rules → Import Settings)
|
||||
- Windsurf (imports `.claude` configs)
|
||||
- Cline, Codex, and other Agent Skills-compatible editors
|
||||
|
||||
**Tasks:**
|
||||
- [x] Create skill template content for `openspec-new-change` (based on current opsx:new)
|
||||
- [x] Create skill template content for `openspec-continue-change` (based on current opsx:continue)
|
||||
- [x] Add temporary `artifact-experimental-setup` command to CLI
|
||||
- [x] Implement skill file generation (YAML frontmatter + markdown body)
|
||||
- [x] Add success message with usage instructions
|
||||
|
||||
**Note:** The `artifact-experimental-setup` command is temporary and will be merged into `openspec init` once the experimental workflow is promoted to stable.
|
||||
|
||||
**Skill Format:**
|
||||
Each skill is a directory with a `SKILL.md` file:
|
||||
```
|
||||
.claude/skills/
|
||||
├── openspec-new-change/
|
||||
│ └── SKILL.md # name, description, instructions
|
||||
├── openspec-continue-change/
|
||||
│ └── SKILL.md # name, description, instructions
|
||||
└── openspec-apply-change/
|
||||
└── SKILL.md # name, description, instructions
|
||||
```
|
||||
|
||||
**CLI Interface:**
|
||||
```bash
|
||||
openspec artifact-experimental-setup
|
||||
|
||||
# Output:
|
||||
# 🧪 Experimental Artifact Workflow Skills Created
|
||||
#
|
||||
# ✓ .claude/skills/openspec-new-change/SKILL.md
|
||||
# ✓ .claude/skills/openspec-continue-change/SKILL.md
|
||||
# ✓ .claude/skills/openspec-apply-change/SKILL.md
|
||||
#
|
||||
# 📖 Usage:
|
||||
#
|
||||
# Skills work automatically in compatible editors:
|
||||
# • Claude Code - Auto-detected, ready to use
|
||||
# • Cursor - Enable in Settings → Rules → Import Settings
|
||||
# • Windsurf - Auto-imports from .claude directory
|
||||
#
|
||||
# Ask Claude naturally:
|
||||
# • "I want to start a new OpenSpec change to add <feature>"
|
||||
# • "Continue working on this change"
|
||||
#
|
||||
# Claude will automatically use the appropriate skill.
|
||||
#
|
||||
# 💡 This is an experimental feature.
|
||||
# Feedback welcome at: https://github.com/Fission-AI/OpenSpec/issues
|
||||
```
|
||||
|
||||
**Implementation Notes:**
|
||||
- Simple file writing: Create directories and write templated `SKILL.md` files (no complex logic)
|
||||
- Use existing `FileSystemUtils.writeFile()` pattern like slash command configurators
|
||||
- Template structure: YAML frontmatter + markdown body
|
||||
- Keep existing `/opsx:*` slash commands for now (manual cleanup later)
|
||||
- Skills use invocation model (user explicitly asks Claude to use them)
|
||||
- Skill `description` field guides when Claude suggests using the skill
|
||||
- Each `SKILL.md` has required fields: `name` (matches directory) and `description`
|
||||
|
||||
---
|
||||
|
||||
### 4. Update `/opsx:new` Command Content
|
||||
|
||||
**Current Behavior (awf:start):**
|
||||
1. Ask user what they want to build (if no input)
|
||||
2. Create change directory
|
||||
3. Show artifact status
|
||||
4. Show what's ready
|
||||
5. Get instructions for proposal
|
||||
6. STOP and wait
|
||||
|
||||
**New Behavior (opsx:new):**
|
||||
Same flow but with updated naming:
|
||||
- References to "awf" → "opsx"
|
||||
- References to `/awf:continue` → `/opsx:continue`
|
||||
- Update frontmatter name/description
|
||||
|
||||
**Tasks:**
|
||||
- [x] Update all "awf" references to "opsx"
|
||||
- [x] Update command references in prompt text
|
||||
- [x] Verify CLI commands still work (they use `openspec`, not `awf`)
|
||||
|
||||
---
|
||||
|
||||
### 5. Update `/opsx:continue` Command Content
|
||||
|
||||
**Current Behavior (awf:continue):**
|
||||
1. Prompt for change selection (if not provided)
|
||||
2. Check current status
|
||||
3. Create ONE artifact based on what's ready
|
||||
4. Show progress and what's unlocked
|
||||
5. STOP
|
||||
|
||||
**New Behavior (opsx:continue):**
|
||||
Same flow with updated naming.
|
||||
|
||||
**Tasks:**
|
||||
- [x] Update all "awf" references to "opsx"
|
||||
- [x] Update command references in prompt text
|
||||
|
||||
---
|
||||
|
||||
### 6. End-to-End Testing
|
||||
|
||||
**Objective:**
|
||||
Run through a complete workflow with Claude using the new skills to create a real feature, validating the entire flow works.
|
||||
|
||||
**Test Scenario:**
|
||||
Use a real OpenSpec feature as the test case (dog-fooding).
|
||||
|
||||
**Test Flow:**
|
||||
1. Run `openspec artifact-experimental-setup` to create skills
|
||||
2. Verify `.claude/skills/openspec-new-change/SKILL.md` created
|
||||
3. Verify `.claude/skills/openspec-continue-change/SKILL.md` created
|
||||
4. Verify `.claude/skills/openspec-apply-change/SKILL.md` created
|
||||
5. Ask Claude: "I want to start a new OpenSpec change to add feature X"
|
||||
6. Verify Claude invokes the `openspec-new-change` skill
|
||||
7. Verify change directory created at `openspec/changes/add-feature-x/`
|
||||
8. Verify proposal template shown
|
||||
9. Ask Claude: "Continue working on this change"
|
||||
10. Verify Claude invokes the `openspec-continue-change` skill
|
||||
11. Verify `proposal.md` created with content
|
||||
12. Ask Claude: "Continue" (create specs)
|
||||
13. Verify `specs/*.md` created
|
||||
14. Ask Claude: "Continue" (create design)
|
||||
15. Verify `design.md` created
|
||||
16. Ask Claude: "Continue" (create tasks)
|
||||
17. Verify `tasks.md` created
|
||||
18. Verify status shows 4/4 complete
|
||||
19. Implement the feature based on tasks
|
||||
20. Run `/openspec:archive` to archive the change
|
||||
|
||||
**Validation Checklist:**
|
||||
- [ ] `openspec artifact-experimental-setup` creates correct directory structure
|
||||
- [ ] Skills are auto-detected in Claude Code
|
||||
- [ ] Skill descriptions trigger appropriate invocations
|
||||
- [ ] Skills create change directory and show proposal template
|
||||
- [ ] Skills correctly identify ready artifacts
|
||||
- [ ] Skills create artifacts with meaningful content
|
||||
- [ ] Dependency detection works (specs requires proposal, etc.)
|
||||
- [ ] Progress tracking is accurate
|
||||
- [ ] Template content is useful and well-structured
|
||||
- [ ] Error handling works (invalid names, missing changes, etc.)
|
||||
- [ ] Works with different schemas (spec-driven, tdd)
|
||||
- [ ] Test in Cursor (Settings → Rules → Import Settings)
|
||||
|
||||
**Document Results:**
|
||||
- Create test log documenting what worked and what didn't
|
||||
- Note any friction points or confusing UX
|
||||
- Identify bugs or improvements needed before user release
|
||||
|
||||
---
|
||||
|
||||
### 7. Documentation for Users
|
||||
|
||||
**Create user-facing documentation explaining:**
|
||||
|
||||
1. **What is the experimental workflow?**
|
||||
- A new way to create OpenSpec changes step-by-step using Agent Skills
|
||||
- One artifact at a time with dependency tracking
|
||||
- More interactive and iterative than the batch approach
|
||||
- Works across Claude Code, Cursor, Windsurf, and other compatible editors
|
||||
|
||||
2. **How to set up experimental workflow**
|
||||
```bash
|
||||
openspec artifact-experimental-setup
|
||||
```
|
||||
|
||||
Note: This is a temporary command that will be integrated into `openspec init` once promoted to stable.
|
||||
|
||||
3. **Available skills**
|
||||
- `openspec-new-change` - Start a new change with artifact workflow
|
||||
- `openspec-continue-change` - Continue working (create next artifact)
|
||||
|
||||
4. **How to use**
|
||||
- **Claude Code**: Skills are auto-detected, just ask Claude naturally
|
||||
- "I want to start a new OpenSpec change to add X"
|
||||
- "Continue working on this change"
|
||||
- **Cursor**: Enable in Settings → Rules → Import Settings
|
||||
- **Windsurf**: Auto-imports `.claude` directory
|
||||
|
||||
5. **Example workflow**
|
||||
- Step-by-step walkthrough with natural language interactions
|
||||
- Show how Claude invokes skills based on user requests
|
||||
|
||||
6. **Feedback mechanism**
|
||||
- GitHub issue template for feedback
|
||||
- What to report (bugs, UX issues, suggestions)
|
||||
|
||||
**Tasks:**
|
||||
- [ ] Create `docs/experimental-workflow.md` user guide
|
||||
- [ ] Add GitHub issue template for experimental feedback
|
||||
- [ ] Update README with mention of experimental features
|
||||
|
||||
---
|
||||
|
||||
## Dependency Graph
|
||||
|
||||
```
|
||||
1. Remove WF skill files
|
||||
└── (no dependencies)
|
||||
|
||||
2. Rename AWF to OPSX
|
||||
└── (no dependencies)
|
||||
|
||||
3. Add Agent Skills
|
||||
└── Depends on: Rename AWF to OPSX (uses opsx content as templates)
|
||||
|
||||
4. Update opsx:new content
|
||||
└── Depends on: Rename AWF to OPSX
|
||||
|
||||
5. Update opsx:continue content
|
||||
└── Depends on: Rename AWF to OPSX
|
||||
|
||||
6. E2E Testing
|
||||
└── Depends on: Add Agent Skills (tests the skills workflow)
|
||||
|
||||
7. User Documentation
|
||||
└── Depends on: E2E Testing (need to know final behavior)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Out of Scope
|
||||
|
||||
The following are explicitly NOT part of this experimental release:
|
||||
|
||||
1. **Batch mode refactor** - Making legacy `/openspec:proposal` use schemas
|
||||
2. **New schemas** - Only shipping with existing `spec-driven` and `tdd`
|
||||
3. **Schema customization UI** - No `openspec schema list` or similar
|
||||
4. **Multiple editor support in CLI** - Skills work cross-editor automatically via `.claude/skills/`
|
||||
5. **Replacing existing commands** - Skills are additive, not replacing `/openspec:*` or `/opsx:*`
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
The experimental release is ready when:
|
||||
|
||||
1. `openspec-new-change`, `openspec-continue-change`, and `openspec-apply-change` skills work end-to-end
|
||||
2. `openspec artifact-experimental-setup` creates skills in `.claude/skills/`
|
||||
3. Skills work in Claude Code and are compatible with Cursor/Windsurf
|
||||
4. At least one complete workflow has been tested manually
|
||||
5. User documentation exists explaining how to generate and use skills
|
||||
6. Feedback mechanism is in place
|
||||
7. WF skill files are removed
|
||||
8. No references to "awf" remain in user-facing content
|
||||
|
||||
---
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Schema selection** - Should `opsx:new` allow selecting a schema, or always use `spec-driven`?
|
||||
- Current: Always uses `spec-driven` as default
|
||||
- Consider: Add `--schema tdd` option or prompt
|
||||
|
||||
2. **Namespace in CLI** - Should experimental CLI commands be namespaced?
|
||||
- Current: `openspec status`, `openspec instructions` (no namespace)
|
||||
- Alternative: `openspec opsx status` (explicit experimental namespace)
|
||||
- Recommendation: Keep current, less typing for users
|
||||
|
||||
3. **Deprecation path** - If opsx becomes the default, how do we migrate?
|
||||
- Not needed for experimental release
|
||||
- Document that command names may change
|
||||
|
||||
---
|
||||
|
||||
## Estimated Work Breakdown
|
||||
|
||||
| Item | Complexity | Notes |
|
||||
|------|------------|-------|
|
||||
| Remove WF files | Trivial | Just delete 2 files + directory |
|
||||
| Rename AWF → OPSX | Low | File renames + content updates |
|
||||
| Add Agent Skills | **Low** | **Simple: 3-4 files, single output directory, standard format** |
|
||||
| Update opsx:new content | Low | Text replacements |
|
||||
| Update opsx:continue content | Low | Text replacements |
|
||||
| E2E Testing | Medium | Manual testing, documenting results |
|
||||
| User Documentation | Medium | New docs, issue template |
|
||||
|
||||
**Key Improvement:** Switching to Agent Skills reduces complexity significantly:
|
||||
- **Before:** 20+ files (type definitions, 18+ editor configurators, editor selection UI)
|
||||
- **After:** 3-4 files (skill templates, simple CLI command)
|
||||
- **Cross-editor:** Works automatically in Claude Code, Cursor, Windsurf without extra code
|
||||
|
||||
---
|
||||
|
||||
## User Feedback from E2E Testing
|
||||
|
||||
### What Worked Well
|
||||
|
||||
1. **Clear dependency graph** ⭐ HIGH PRIORITY - KEEP
|
||||
- The status command showing blocked/unblocked artifacts was intuitive:
|
||||
```
|
||||
[x] proposal
|
||||
[ ] design
|
||||
[-] tasks (blocked by: design, specs)
|
||||
```
|
||||
- Users always knew what they could work on next
|
||||
- **Relevance**: Core UX strength to preserve
|
||||
|
||||
2. **Structured instructions output** ⭐ HIGH PRIORITY - KEEP
|
||||
- `openspec instructions <artifact>` gave templates, output paths, and context in one call
|
||||
- Very helpful for understanding what to create
|
||||
- **Relevance**: Essential for agent-driven workflow
|
||||
|
||||
3. **Simple scaffolding** ✅ WORKS WELL
|
||||
- `openspec new change "name"` just worked - created directory structure without fuss
|
||||
- **Relevance**: Good baseline, room for improvement (see pain points)
|
||||
|
||||
---
|
||||
|
||||
### Pain Points & Confusion
|
||||
|
||||
1. **Redundant CLI calls** ⚠️ MEDIUM PRIORITY
|
||||
- Users called both `status` AND `next` every time, but they overlap significantly
|
||||
- `status` already shows what's blocked
|
||||
- **Recommendation**: Consider merging or making `next` give actionable guidance beyond just listing names
|
||||
- **Relevance**: Reduces friction in iterative workflow
|
||||
|
||||
2. **Specs directory structure was ambiguous** 🔥 HIGH PRIORITY - FIX
|
||||
- Instructions said: `Write to: .../specs/**/*.md`
|
||||
- Users had to guess: `specs/spec.md`? `specs/game/spec.md`? `specs/tic-tac-toe/spec.md`?
|
||||
- Users ended up doing manual `mkdir -p .../specs/tic-tac-toe` then writing `spec.md` inside
|
||||
- **Recommendation**: CLI should scaffold this directory structure automatically
|
||||
- **Relevance**: Critical agent UX - ambiguous paths cause workflow friction
|
||||
|
||||
3. **Repetitive --change flag** ⚠️ MEDIUM PRIORITY
|
||||
- Every command needed `--change "tic-tac-toe-game"`
|
||||
- After 10+ calls, this felt verbose
|
||||
- **Recommendation**: `openspec use "tic-tac-toe-game"` to set context, then subsequent commands assume that change
|
||||
- **Relevance**: Quality of life improvement for iterative sessions
|
||||
|
||||
4. **No validation feedback** 🔥 HIGH PRIORITY - ADD
|
||||
- After writing each artifact, users just ran `status` hoping it would show `[x]`
|
||||
- Questions raised:
|
||||
- How did it know the artifact was "done"? File existence?
|
||||
- What if spec format was wrong (e.g., wrong heading levels)?
|
||||
- **Recommendation**: Add `openspec validate --change "name"` to check content quality
|
||||
- **Relevance**: Critical for user confidence and catching errors early
|
||||
|
||||
5. **Query-heavy, action-light CLI** 🔥 HIGH PRIORITY - ENHANCE
|
||||
- Most commands retrieve info. The only "action" is `new change`
|
||||
- Artifact creation is manual Write to guessed paths
|
||||
- **Recommendation**: `openspec create proposal --change "name"` could scaffold the file with template pre-filled, then user just edits
|
||||
- **Relevance**: Directly impacts agent productivity - reduce manual file writing
|
||||
|
||||
6. **Instructions output was verbose** ⚠️ LOW PRIORITY
|
||||
- XML-style output (`<artifact>`, `<template>`, `<instruction>`) was parseable but long
|
||||
- Key info (output path, template) was buried in ~50 lines
|
||||
- **Recommendation**: Add compact mode or structured JSON output for agents
|
||||
- **Relevance**: Nice-to-have for agent parsing efficiency
|
||||
|
||||
---
|
||||
|
||||
### Workflow Friction
|
||||
|
||||
1. **Mandatory "STOP and wait" after showing proposal template** ⚠️ MEDIUM PRIORITY
|
||||
- The skill said "STOP and wait" after showing the proposal template
|
||||
- This felt overly cautious when user had already provided enough context (e.g., "tic tac toe, single player vs AI, minimal aesthetics")
|
||||
- **Recommendation**: Make the pause optional or conditional based on context clarity
|
||||
- **Relevance**: Reduces unnecessary round-trips in agent conversations
|
||||
|
||||
2. **No connection to implementation** 🔥 HIGH PRIORITY - ROADMAP ITEM
|
||||
- After 4/4 artifacts complete, then what? The workflow ends at planning
|
||||
- No `openspec apply` or guidance on how to execute the tasks
|
||||
- User asked "would you like me to implement?" but that's outside OpenSpec's scope currently
|
||||
- **Recommendation**: Add implementation bridge - either:
|
||||
- `openspec apply` command to start execution phase
|
||||
- Clear handoff to existing `/openspec:apply` workflow
|
||||
- Documentation on next steps after planning completes
|
||||
- **Relevance**: Critical missing piece - users expect end-to-end workflow
|
||||
|
||||
---
|
||||
|
||||
### Priority Summary
|
||||
|
||||
**MUST FIX (High Priority):**
|
||||
1. Specs directory structure ambiguity (#2)
|
||||
2. Add validation feedback (#4)
|
||||
3. Make CLI more action-oriented (#5)
|
||||
4. Bridge to implementation phase (#2 in Workflow Friction)
|
||||
5. Keep clear dependency graph (#1 in What Worked)
|
||||
6. Keep structured instructions (#2 in What Worked)
|
||||
|
||||
**SHOULD FIX (Medium Priority):**
|
||||
1. Reduce redundant CLI calls (#1)
|
||||
2. Repetitive `--change` flag (#3)
|
||||
3. Mandatory STOP behavior (#1 in Workflow Friction)
|
||||
|
||||
**NICE TO HAVE (Low Priority):**
|
||||
1. Compact instructions output mode (#6)
|
||||
|
||||
---
|
||||
|
||||
## Design Decisions (from E2E Testing Feedback)
|
||||
|
||||
Based on dev testing and analysis of agent workflow friction, we identified three blockers for experimental release and made the following decisions.
|
||||
|
||||
### Blockers Identified
|
||||
|
||||
From the pain points in E2E testing, three issues are blocking the experimental release:
|
||||
|
||||
1. **Specs directory ambiguity** - Agents don't know where to write spec files or how to name capabilities
|
||||
2. **CLI is query-heavy** - Most commands retrieve info, artifact creation is manual
|
||||
3. **Apply integration missing** - After 4/4 artifacts complete, no guidance on implementation phase
|
||||
|
||||
### Decision 1: Capability Discovery in Proposal (RESOLVED)
|
||||
|
||||
**Problem:** The specs artifact instruction says "Create one spec file per capability in `specs/<name>/spec.md`" but:
|
||||
- Agent doesn't know what `<name>` should be
|
||||
- Capability identification requires research (existing specs, codebase)
|
||||
- Proposal template asks for "Affected specs" but doesn't structure it
|
||||
- Research happens implicitly, output isn't captured
|
||||
|
||||
**Decision:** Enrich the proposal template to explicitly capture capability discovery.
|
||||
|
||||
**Current proposal template:**
|
||||
```markdown
|
||||
## Why
|
||||
## What Changes
|
||||
## Impact
|
||||
- Affected specs: List capabilities... ← vague, easy to skip
|
||||
- Affected code: ...
|
||||
```
|
||||
|
||||
**New proposal template:**
|
||||
```markdown
|
||||
## Why
|
||||
## What Changes
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
<!-- Capabilities being introduced (will create new specs/<name>/spec.md) -->
|
||||
- `<name>`: <brief description of what this capability covers>
|
||||
|
||||
### Modified Capabilities
|
||||
<!-- Existing capabilities being changed (will update existing specs) -->
|
||||
- `<existing-name>`: <what's changing>
|
||||
|
||||
## Impact
|
||||
<!-- Affected code, APIs, dependencies, systems -->
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- Proposal already asks for capabilities (just poorly) - this makes it explicit
|
||||
- Captured output is reviewable (vs implicit research that can't be verified)
|
||||
- Creates clear contract between proposal and specs phases
|
||||
- Distinguishes NEW vs MODIFIED upfront (critical for specs phase)
|
||||
- Agent can't skip research - it's part of the deliverable
|
||||
|
||||
**Implementation:**
|
||||
- Update `schemas/spec-driven/templates/proposal.md`
|
||||
- Update proposal instruction in `schemas/spec-driven/schema.yaml`
|
||||
- Update skill instructions to guide capability discovery
|
||||
|
||||
### Decision 2: CLI Action Commands (IN PROGRESS)
|
||||
|
||||
**Problem:** CLI is mostly query-oriented. Agents run `openspec status`, `openspec next`, `openspec instructions` but then must manually write files.
|
||||
|
||||
#### Decision 2a: Remove `openspec next` command (RESOLVED)
|
||||
|
||||
**Problem:** The `next` command is redundant. It only shows which artifacts are ready, but `status` already shows this information (artifacts with status "ready" vs "blocked" vs "done").
|
||||
|
||||
**Current behavior:**
|
||||
```bash
|
||||
openspec status --change "X" # Shows: proposal (done), specs (ready), design (blocked), tasks (blocked)
|
||||
openspec next --change "X" # Shows: ["specs"] ← redundant
|
||||
```
|
||||
|
||||
**Decision:** Remove the `next` command. Agents should use `status` which provides the same info plus more context.
|
||||
|
||||
**Implementation:**
|
||||
- Remove `next` command from CLI
|
||||
- Update skill instructions to use `status` instead of `next`
|
||||
- Update AGENTS.md references
|
||||
|
||||
#### Decision 2b: CLI Scaffolding (RESOLVED - NO)
|
||||
|
||||
**Problem:** After getting instructions, agents manually write files. Should CLI scaffold artifacts instead?
|
||||
|
||||
**Options considered:**
|
||||
- Add `openspec create <artifact>` commands that scaffold files with templates
|
||||
- Keep current approach where agent writes files directly from instructions
|
||||
- Hybrid: CLI can scaffold, agent can also write directly
|
||||
|
||||
**Decision:** Keep current flow. No scaffolding commands.
|
||||
|
||||
**Rationale (from agent ergonomics perspective):**
|
||||
- One Write is better than multiple Edits - agent composes full content atomically
|
||||
- `instructions` already provides template in context - scaffolding just moves it to a file
|
||||
- Fewer tool calls: `instructions` + Write (2) vs `create` + `instructions` + Read + Edit×N (4+)
|
||||
- Scaffolding doesn't solve the real problem (not knowing WHAT to write)
|
||||
- Real problem solved by proposal template change (capability discovery)
|
||||
|
||||
**For multi-file artifacts (specs):** Scaffolding can't help because CLI doesn't know capability names until proposal is complete. The capability discovery in proposal solves this.
|
||||
|
||||
### Decision 3: Apply Integration (RESOLVED)
|
||||
|
||||
**Original problem:** After planning completes (4/4 artifacts), the experimental workflow ends. No guidance on implementation.
|
||||
|
||||
**Key insight: No phases, just actions.**
|
||||
|
||||
Through discussion, we realized phases (planning → implementation → archive) are an artificial constraint. Work is fluid:
|
||||
- You might start implementing, realize the design is wrong → update design.md
|
||||
- You're halfway through tasks, discover a new requirement → update specs
|
||||
- You bounce between "planning" and "implementing" constantly
|
||||
|
||||
**The better model: Actions on a Change**
|
||||
|
||||
A change is a thing (with artifacts). Actions are verbs you perform on a change. Actions aren't phases - they're fluid operations you can perform anytime.
|
||||
|
||||
| Action | What it does | Skill | CLI Command |
|
||||
|--------|--------------|-------|-------------|
|
||||
| `new` | Create a change (scaffold directory) | `opsx:new` | `openspec new change` |
|
||||
| `continue` | Create next artifact (dependency-aware) | `opsx:continue` | `openspec instructions` |
|
||||
| `apply` | Implement tasks (execute, check off) | `opsx:apply` (NEW) | TBD |
|
||||
| `update` | Refresh/update artifacts based on learnings | `opsx:update` (NEW) | TBD |
|
||||
| `explore` | Research, ask questions, understand | `opsx:explore` (NEW) | TBD |
|
||||
| `validate` | Check artifacts are correct/complete | TBD | `openspec validate` |
|
||||
| `archive` | Finalize and move to archive | existing | `openspec archive` |
|
||||
|
||||
**Key principles:**
|
||||
- Actions are modeled as skills (primary interface for agents)
|
||||
- Some skills have matching CLI commands for convenience
|
||||
- Skills and CLI commands are decoupled - not everything needs both
|
||||
- Actions can be performed in any order (with soft prerequisites)
|
||||
- No linear phase gates
|
||||
|
||||
**What the schema defines:**
|
||||
- Artifacts (what they are, where they go)
|
||||
- Dependencies (what must exist first)
|
||||
- Required vs optional
|
||||
- Templates + instructions
|
||||
|
||||
**What the schema does NOT define:**
|
||||
- Phases
|
||||
- When you can modify things
|
||||
- Linear workflow
|
||||
|
||||
**Progress tracking:**
|
||||
- tasks.md checkboxes = implementation progress
|
||||
- Artifact existence = planning progress
|
||||
- Archive readiness = user decides (or all tasks done)
|
||||
|
||||
**For experimental release:**
|
||||
- Create `opsx:apply` skill (guidance for implementing tasks)
|
||||
- Document the "actions on a change" model
|
||||
- Other actions (update, explore) can come later
|
||||
|
||||
---
|
||||
|
||||
### Design: `openspec-apply-change` Skill
|
||||
|
||||
#### Overview
|
||||
|
||||
The apply skill guides agents through implementing tasks from a completed (or in-progress) change. Unlike the old `/openspec:apply` command, this skill:
|
||||
- Is **fluid** - can be invoked anytime, not just after all artifacts are done
|
||||
- Allows **artifact updates** - if implementation reveals issues, update design/specs
|
||||
- Works **until done** - keeps going through tasks until complete or blocked
|
||||
- Tracks **progress via checkboxes** - tasks.md is the source of truth
|
||||
|
||||
#### Skill Metadata
|
||||
|
||||
```yaml
|
||||
name: openspec-apply-change
|
||||
description: Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.
|
||||
```
|
||||
|
||||
#### When to Invoke
|
||||
|
||||
The skill should be invoked when:
|
||||
- User says "implement this change" or "start implementing"
|
||||
- User says "work on the tasks" or "do the next task"
|
||||
- User says "apply this change"
|
||||
- All artifacts are complete and user wants to proceed
|
||||
- User wants to continue implementation after a break
|
||||
|
||||
#### Input
|
||||
|
||||
- Optionally: change name
|
||||
- Optionally: specific task number to work on
|
||||
- If omitted: prompt for change selection (same pattern as continue-change)
|
||||
|
||||
#### Steps
|
||||
|
||||
```markdown
|
||||
**Steps**
|
||||
|
||||
1. **If no change name provided, prompt for selection**
|
||||
|
||||
Run `openspec list --json` to get available changes. Use **AskUserQuestion** to let user select.
|
||||
|
||||
Show changes that have tasks.md (implementation-ready).
|
||||
Mark changes with incomplete tasks as "(In Progress)".
|
||||
|
||||
2. **Get apply instructions**
|
||||
|
||||
```bash
|
||||
openspec instructions apply --change "<name>" --json
|
||||
```
|
||||
|
||||
This returns:
|
||||
- Context file paths (proposal, specs, design, tasks)
|
||||
- Progress (total, complete, remaining)
|
||||
- Task list with status
|
||||
- Dynamic instruction based on current state
|
||||
|
||||
**Handle states:**
|
||||
- If blocked (missing artifacts): show message, suggest `openspec-continue-change`
|
||||
- If all done: congratulate, suggest archive
|
||||
- Otherwise: proceed to implementation
|
||||
|
||||
3. **Read context files**
|
||||
|
||||
Read the files listed in the instructions:
|
||||
- `proposal.md` - why and what
|
||||
- `specs/*.md` - requirements and scenarios
|
||||
- `design.md` - technical approach (if exists)
|
||||
- `tasks.md` - the implementation checklist
|
||||
|
||||
4. **Show current progress**
|
||||
|
||||
Display:
|
||||
- Progress: "N/M tasks complete"
|
||||
- Remaining tasks overview
|
||||
- Dynamic instruction from CLI
|
||||
|
||||
5. **Implement tasks (loop until done or blocked)**
|
||||
|
||||
For each pending task:
|
||||
- Show which task is being worked on
|
||||
- Make the code changes required
|
||||
- Keep changes minimal and focused
|
||||
- Mark task complete in tasks.md: `- [ ]` → `- [x]`
|
||||
- Continue to next task
|
||||
|
||||
**Pause if:**
|
||||
- Task is unclear → ask for clarification
|
||||
- Implementation reveals a design issue → suggest updating artifacts
|
||||
- Error or blocker encountered → report and wait for guidance
|
||||
- User interrupts
|
||||
|
||||
6. **On completion or pause, show status**
|
||||
|
||||
Display:
|
||||
- Tasks completed this session
|
||||
- Overall progress: "N/M tasks complete"
|
||||
- If all done: suggest archive
|
||||
- If paused: explain why and wait for guidance
|
||||
```
|
||||
|
||||
#### Output Format
|
||||
|
||||
**During implementation:**
|
||||
```
|
||||
## Implementing: add-user-auth
|
||||
|
||||
Working on task 3/7: Create UserAuth service class
|
||||
[...implementation happening...]
|
||||
✓ Task complete
|
||||
|
||||
Working on task 4/7: Add login endpoint to AuthController
|
||||
[...implementation happening...]
|
||||
✓ Task complete
|
||||
|
||||
Working on task 5/7: Add JWT token generation
|
||||
[...implementation happening...]
|
||||
```
|
||||
|
||||
**On completion:**
|
||||
```
|
||||
## Implementation Complete
|
||||
|
||||
**Change:** add-user-auth
|
||||
**Progress:** 7/7 tasks complete ✓
|
||||
|
||||
### Completed This Session
|
||||
- [x] Create UserAuth service class
|
||||
- [x] Add login endpoint to AuthController
|
||||
- [x] Add JWT token generation
|
||||
- [x] Add logout endpoint
|
||||
- [x] Add auth middleware
|
||||
- [x] Write unit tests
|
||||
- [x] Update API documentation
|
||||
|
||||
All tasks complete! Ready to archive this change.
|
||||
```
|
||||
|
||||
**On pause (issue encountered):**
|
||||
```
|
||||
## Implementation Paused
|
||||
|
||||
**Change:** add-user-auth
|
||||
**Progress:** 4/7 tasks complete
|
||||
|
||||
### Issue Encountered
|
||||
Task 5 "Add JWT token generation" - the design specifies using RS256 but
|
||||
the existing auth library only supports HS256.
|
||||
|
||||
**Options:**
|
||||
1. Update design.md to use HS256 instead
|
||||
2. Add a new JWT library that supports RS256
|
||||
3. Other approach
|
||||
|
||||
What would you like to do?
|
||||
```
|
||||
|
||||
#### Guardrails
|
||||
|
||||
- Keep going through tasks until done or blocked
|
||||
- Always read context before starting (specs, design)
|
||||
- If task is ambiguous, pause and ask before implementing
|
||||
- If implementation reveals issues, pause and suggest artifact updates
|
||||
- Keep code changes minimal and scoped to each task
|
||||
- Update task checkbox immediately after completing each task
|
||||
- Pause on errors, blockers, or unclear requirements - don't guess
|
||||
|
||||
#### Fluid Workflow Integration
|
||||
|
||||
The apply skill supports the "actions on a change" model:
|
||||
|
||||
**Can be invoked anytime:**
|
||||
- Before all artifacts are done (if tasks.md exists)
|
||||
- After partial implementation
|
||||
- Interleaved with other actions (update, continue)
|
||||
|
||||
**Allows artifact updates:**
|
||||
- If implementation reveals design issues → suggest `opsx:update` or manual edit
|
||||
- If requirements need clarification → suggest updating specs
|
||||
- Not phase-locked - work fluidly
|
||||
|
||||
**Example fluid workflow:**
|
||||
```
|
||||
User: "Implement add-user-auth"
|
||||
→ openspec-apply-change: implements tasks 1, 2, 3, 4...
|
||||
→ Pauses at task 5: "Design says RS256 but library only supports HS256"
|
||||
|
||||
User: "Let's use HS256 instead, update the design"
|
||||
→ User edits design.md (or uses opsx:update in future)
|
||||
|
||||
User: "Continue implementing"
|
||||
→ openspec-apply-change: implements tasks 5, 6, 7
|
||||
→ "All tasks complete! Ready to archive."
|
||||
```
|
||||
|
||||
#### CLI Commands Used
|
||||
|
||||
```bash
|
||||
openspec list --json # List changes for selection
|
||||
openspec status --change "<name>" # Check artifact completion
|
||||
openspec instructions apply --change "<name>" # Get apply instructions (NEW)
|
||||
# File reads via Read tool for proposal, specs, design, tasks
|
||||
# File edits via Edit tool for checking off tasks
|
||||
```
|
||||
|
||||
#### New CLI Command: `openspec instructions apply`
|
||||
|
||||
For consistency with artifact instructions.
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
openspec instructions apply --change "<name>" [--json]
|
||||
```
|
||||
|
||||
**Output (Markdown format):**
|
||||
```markdown
|
||||
## Apply: add-user-auth
|
||||
|
||||
### Context Files
|
||||
- proposal: openspec/changes/add-user-auth/proposal.md
|
||||
- specs: openspec/changes/add-user-auth/specs/**/*.md
|
||||
- design: openspec/changes/add-user-auth/design.md
|
||||
- tasks: openspec/changes/add-user-auth/tasks.md
|
||||
|
||||
### Progress
|
||||
2/7 complete
|
||||
|
||||
### Tasks
|
||||
- [x] Create UserAuth service class
|
||||
- [x] Add login endpoint
|
||||
- [ ] Add JWT token generation
|
||||
- [ ] Add logout endpoint
|
||||
- [ ] Add auth middleware
|
||||
- [ ] Write unit tests
|
||||
- [ ] Update API documentation
|
||||
|
||||
### Instruction
|
||||
Read context files, work through pending tasks, mark complete as you go.
|
||||
Pause if you hit blockers or need clarification.
|
||||
```
|
||||
|
||||
**Benefits of CLI command:**
|
||||
- **Consistency** - same pattern as `openspec instructions <artifact>`
|
||||
- **Structured output** - progress, tasks, context paths in one call
|
||||
- **Clean format** - markdown is readable and compact (vs verbose XML)
|
||||
- **Extensibility** - can add more sections later if needed
|
||||
- **JSON option** - `--json` flag available for programmatic use
|
||||
|
||||
#### Differences from Old `/openspec:apply`
|
||||
|
||||
| Aspect | Old `/openspec:apply` | New `openspec-apply-change` |
|
||||
|--------|----------------------|----------------------------|
|
||||
| Invocation | After all artifacts done | Anytime (if tasks.md exists) |
|
||||
| Granularity | All tasks at once | All tasks, but pauses on issues |
|
||||
| Artifact updates | Not mentioned | Encouraged when needed |
|
||||
| Progress tracking | Update all at end | Update after each task |
|
||||
| Flow control | Push through everything | Pause on blockers, resume after |
|
||||
| Context loading | Read once at start | Read context, reference as needed |
|
||||
| Issue handling | Not specified | Pause, present options, wait for guidance |
|
||||
|
||||
#### Implementation Notes
|
||||
|
||||
1. **Add CLI command**: Add `openspec instructions apply` to artifact-workflow.ts
|
||||
- Parse tasks.md for progress (count done/pending)
|
||||
- Return context paths, progress, task list, simple instruction
|
||||
2. **Add to skill-templates.ts**: Create `getApplyChangeSkillTemplate()` function
|
||||
3. **Update artifact-experimental-setup**: Generate this skill alongside new/continue
|
||||
4. **Update skills list**: Add to `.claude/skills/` directory
|
||||
5. **Test the flow**: Verify it works with existing changes that have tasks.md
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ~~Review this plan and confirm scope~~ (Done - blockers identified)
|
||||
2. ~~Design decisions~~ (Done - all 3 blockers resolved)
|
||||
3. ~~Design apply skill~~ (Done - documented above)
|
||||
4. ~~Implement proposal template change (Decision 1 - capability discovery)~~ (Done)
|
||||
5. ~~Remove `openspec next` command (Decision 2a)~~ (Done)
|
||||
6. ~~Add `openspec instructions apply` CLI command~~ (Done)
|
||||
7. ~~Create `openspec-apply-change` skill~~ (Done)
|
||||
8. Conduct E2E testing with updated workflow
|
||||
9. Write user docs (document "actions on a change" model)
|
||||
10. Release to test users
|
||||
@@ -0,0 +1,665 @@
|
||||
# Experimental Workflow (OPSX)
|
||||
|
||||
> **Status:** Experimental. Things might break. Feedback welcome on [Discord](https://discord.gg/YctCnvvshC).
|
||||
>
|
||||
> **Compatibility:** Claude Code only (for now)
|
||||
|
||||
## What Is It?
|
||||
|
||||
OPSX is a **fluid, iterative workflow** for OpenSpec changes. No more rigid phases — just actions you can take anytime.
|
||||
|
||||
## Why This Exists
|
||||
|
||||
The standard OpenSpec workflow works, but it's **locked down**:
|
||||
|
||||
- **Instructions are hardcoded** — buried in TypeScript, you can't change them
|
||||
- **All-or-nothing** — one big command creates everything, can't test individual pieces
|
||||
- **Fixed structure** — same workflow for everyone, no customization
|
||||
- **Black box** — when AI output is bad, you can't tweak the prompts
|
||||
|
||||
**OPSX opens it up.** Now anyone can:
|
||||
|
||||
1. **Experiment with instructions** — edit a template, see if the AI does better
|
||||
2. **Test granularly** — validate each artifact's instructions independently
|
||||
3. **Customize workflows** — define your own artifacts and dependencies
|
||||
4. **Iterate quickly** — change a template, test immediately, no rebuild
|
||||
|
||||
```
|
||||
Standard workflow: OPSX:
|
||||
┌────────────────────────┐ ┌────────────────────────┐
|
||||
│ Hardcoded in package │ │ schema.yaml │◄── You edit this
|
||||
│ (can't change) │ │ templates/*.md │◄── Or this
|
||||
│ ↓ │ │ ↓ │
|
||||
│ Wait for new release │ │ Instant effect │
|
||||
│ ↓ │ │ ↓ │
|
||||
│ Hope it's better │ │ Test it yourself │
|
||||
└────────────────────────┘ └────────────────────────┘
|
||||
```
|
||||
|
||||
**This is for everyone:**
|
||||
- **Teams** — create workflows that match how you actually work
|
||||
- **Power users** — tweak prompts to get better AI outputs for your codebase
|
||||
- **OpenSpec contributors** — experiment with new approaches without releases
|
||||
|
||||
We're all still learning what works best. OPSX lets us learn together.
|
||||
|
||||
## The User Experience
|
||||
|
||||
**The problem with linear workflows:**
|
||||
You're "in planning phase", then "in implementation phase", then "done". But real work doesn't work that way. You implement something, realize your design was wrong, need to update specs, continue implementing. Linear phases fight against how work actually happens.
|
||||
|
||||
**OPSX approach:**
|
||||
- **Actions, not phases** — create, implement, update, archive — do any of them anytime
|
||||
- **Dependencies are enablers** — they show what's possible, not what's required next
|
||||
- **Update as you learn** — halfway through implementation? Go back and fix the design. That's normal.
|
||||
|
||||
```
|
||||
You can always go back:
|
||||
|
||||
┌────────────────────────────────────┐
|
||||
│ │
|
||||
▼ │
|
||||
proposal ──→ specs ──→ design ──→ tasks ──→ implement
|
||||
▲ ▲ ▲ │
|
||||
│ │ │ │
|
||||
└───────────┴──────────┴───────────────┘
|
||||
update as you learn
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
# 1. Make sure you have openspec installed and initialized
|
||||
openspec init
|
||||
|
||||
# 2. Generate the experimental skills
|
||||
openspec experimental
|
||||
```
|
||||
|
||||
This creates skills in `.claude/skills/` that Claude Code auto-detects.
|
||||
|
||||
During setup, you'll be prompted to create a **project config** (`openspec/config.yaml`). This is optional but recommended.
|
||||
|
||||
## Project Configuration
|
||||
|
||||
Project config lets you set defaults and inject project-specific context into all artifacts.
|
||||
|
||||
### Creating Config
|
||||
|
||||
Config is created during `experimental`, or manually:
|
||||
|
||||
```yaml
|
||||
# openspec/config.yaml
|
||||
schema: spec-driven
|
||||
|
||||
context: |
|
||||
Tech stack: TypeScript, React, Node.js
|
||||
API conventions: RESTful, JSON responses
|
||||
Testing: Vitest for unit tests, Playwright for e2e
|
||||
Style: ESLint with Prettier, strict TypeScript
|
||||
|
||||
rules:
|
||||
proposal:
|
||||
- Include rollback plan
|
||||
- Identify affected teams
|
||||
specs:
|
||||
- Use Given/When/Then format for scenarios
|
||||
design:
|
||||
- Include sequence diagrams for complex flows
|
||||
```
|
||||
|
||||
### Config Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `schema` | string | Default schema for new changes (e.g., `spec-driven`, `tdd`) |
|
||||
| `context` | string | Project context injected into all artifact instructions |
|
||||
| `rules` | object | Per-artifact rules, keyed by artifact ID |
|
||||
|
||||
### How It Works
|
||||
|
||||
**Schema precedence** (highest to lowest):
|
||||
1. CLI flag (`--schema tdd`)
|
||||
2. Change metadata (`.openspec.yaml` in change directory)
|
||||
3. Project config (`openspec/config.yaml`)
|
||||
4. Default (`spec-driven`)
|
||||
|
||||
**Context injection:**
|
||||
- Context is prepended to every artifact's instructions
|
||||
- Wrapped in `<context>...</context>` tags
|
||||
- Helps AI understand your project's conventions
|
||||
|
||||
**Rules injection:**
|
||||
- Rules are only injected for matching artifacts
|
||||
- Wrapped in `<rules>...</rules>` tags
|
||||
- Appear after context, before the template
|
||||
|
||||
### Artifact IDs by Schema
|
||||
|
||||
**spec-driven** (default):
|
||||
- `proposal` — Change proposal
|
||||
- `specs` — Specifications
|
||||
- `design` — Technical design
|
||||
- `tasks` — Implementation tasks
|
||||
|
||||
**tdd**:
|
||||
- `spec` — Feature specification
|
||||
- `tests` — Test file
|
||||
- `implementation` — Implementation code
|
||||
- `docs` — Documentation
|
||||
|
||||
### Config Validation
|
||||
|
||||
- Unknown artifact IDs in `rules` generate warnings
|
||||
- Schema names are validated against available schemas
|
||||
- Context has a 50KB size limit
|
||||
- Invalid YAML is reported with line numbers
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
**"Unknown artifact ID in rules: X"**
|
||||
- Check artifact IDs match your schema (see list above)
|
||||
- Run `openspec schemas --json` to see artifact IDs for each schema
|
||||
|
||||
**Config not being applied:**
|
||||
- Ensure file is at `openspec/config.yaml` (not `.yml`)
|
||||
- Check YAML syntax with a validator
|
||||
- Config changes take effect immediately (no restart needed)
|
||||
|
||||
**Context too large:**
|
||||
- Context is limited to 50KB
|
||||
- Summarize or link to external docs instead
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | What it does |
|
||||
|---------|--------------|
|
||||
| `/opsx:explore` | Think through ideas, investigate problems, clarify requirements |
|
||||
| `/opsx:new` | Start a new change |
|
||||
| `/opsx:continue` | Create the next artifact (based on what's ready) |
|
||||
| `/opsx:ff` | Fast-forward — create all planning artifacts at once |
|
||||
| `/opsx:apply` | Implement tasks, updating artifacts as needed |
|
||||
| `/opsx:sync` | Sync delta specs to main specs |
|
||||
| `/opsx:archive` | Archive when done |
|
||||
|
||||
## Usage
|
||||
|
||||
### Explore an idea
|
||||
```
|
||||
/opsx:explore
|
||||
```
|
||||
Think through ideas, investigate problems, compare options. No structure required - just a thinking partner. When insights crystallize, transition to `/opsx:new` or `/opsx:ff`.
|
||||
|
||||
### Start a new change
|
||||
```
|
||||
/opsx:new
|
||||
```
|
||||
You'll be asked what you want to build and which workflow schema to use.
|
||||
|
||||
### Create artifacts
|
||||
```
|
||||
/opsx:continue
|
||||
```
|
||||
Shows what's ready to create based on dependencies, then creates one artifact. Use repeatedly to build up your change incrementally.
|
||||
|
||||
```
|
||||
/opsx:ff add-dark-mode
|
||||
```
|
||||
Creates all planning artifacts at once. Use when you have a clear picture of what you're building.
|
||||
|
||||
### Implement (the fluid part)
|
||||
```
|
||||
/opsx:apply
|
||||
```
|
||||
Works through tasks, checking them off as you go. **Key difference:** if you discover issues during implementation, you can update your specs, design, or tasks — then continue. No phase gates. If you're juggling multiple changes, you can run `/opsx:apply <name>`; otherwise it should infer from the conversation and prompt you to choose if it can’t tell.
|
||||
|
||||
### Finish up
|
||||
```
|
||||
/opsx:sync # Update main specs with your delta specs
|
||||
/opsx:archive # Move to archive when done
|
||||
```
|
||||
|
||||
## When to Update vs. Start Fresh
|
||||
|
||||
OPSX lets you update artifacts anytime. But when does "update as you learn" become "this is different work"?
|
||||
|
||||
### What a Proposal Captures
|
||||
|
||||
A proposal defines three things:
|
||||
1. **Intent** — What problem are you solving?
|
||||
2. **Scope** — What's in/out of bounds?
|
||||
3. **Approach** — How will you solve it?
|
||||
|
||||
The question is: which changed, and by how much?
|
||||
|
||||
### Update the Existing Change When:
|
||||
|
||||
**Same intent, refined execution**
|
||||
- You discover edge cases you didn't consider
|
||||
- The approach needs tweaking but the goal is unchanged
|
||||
- Implementation reveals the design was slightly off
|
||||
|
||||
**Scope narrows**
|
||||
- You realize full scope is too big, want to ship MVP first
|
||||
- "Add dark mode" → "Add dark mode toggle (system preference in v2)"
|
||||
|
||||
**Learning-driven corrections**
|
||||
- Codebase isn't structured how you thought
|
||||
- A dependency doesn't work as expected
|
||||
- "Use CSS variables" → "Use Tailwind's dark: prefix instead"
|
||||
|
||||
### Start a New Change When:
|
||||
|
||||
**Intent fundamentally changed**
|
||||
- The problem itself is different now
|
||||
- "Add dark mode" → "Add comprehensive theme system with custom colors, fonts, spacing"
|
||||
|
||||
**Scope exploded**
|
||||
- Change grew so much it's essentially different work
|
||||
- Original proposal would be unrecognizable after updates
|
||||
- "Fix login bug" → "Rewrite auth system"
|
||||
|
||||
**Original is completable**
|
||||
- The original change can be marked "done"
|
||||
- New work stands alone, not a refinement
|
||||
- Complete "Add dark mode MVP" → Archive → New change "Enhance dark mode"
|
||||
|
||||
### The Heuristics
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Is this the same work? │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
┌──────────────────┼──────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
Same intent? >50% overlap? Can original
|
||||
Same problem? Same scope? be "done" without
|
||||
│ │ these changes?
|
||||
│ │ │
|
||||
┌────────┴────────┐ ┌──────┴──────┐ ┌───────┴───────┐
|
||||
│ │ │ │ │ │
|
||||
YES NO YES NO NO YES
|
||||
│ │ │ │ │ │
|
||||
▼ ▼ ▼ ▼ ▼ ▼
|
||||
UPDATE NEW UPDATE NEW UPDATE NEW
|
||||
```
|
||||
|
||||
| Test | Update | New Change |
|
||||
|------|--------|------------|
|
||||
| **Identity** | "Same thing, refined" | "Different work" |
|
||||
| **Scope overlap** | >50% overlaps | <50% overlaps |
|
||||
| **Completion** | Can't be "done" without changes | Can finish original, new work stands alone |
|
||||
| **Story** | Update chain tells coherent story | Patches would confuse more than clarify |
|
||||
|
||||
### The Principle
|
||||
|
||||
> **Update preserves context. New change provides clarity.**
|
||||
>
|
||||
> Choose update when the history of your thinking is valuable.
|
||||
> Choose new when starting fresh would be clearer than patching.
|
||||
|
||||
Think of it like git branches:
|
||||
- Keep committing while working on the same feature
|
||||
- Start a new branch when it's genuinely new work
|
||||
- Sometimes merge a partial feature and start fresh for phase 2
|
||||
|
||||
## What's Different?
|
||||
|
||||
| | Standard (`/openspec:proposal`) | Experimental (`/opsx:*`) |
|
||||
|---|---|---|
|
||||
| **Structure** | One big proposal document | Discrete artifacts with dependencies |
|
||||
| **Workflow** | Linear phases: plan → implement → archive | Fluid actions — do anything anytime |
|
||||
| **Iteration** | Awkward to go back | Update artifacts as you learn |
|
||||
| **Customization** | Fixed structure | Schema-driven (define your own artifacts) |
|
||||
|
||||
**The key insight:** work isn't linear. OPSX stops pretending it is.
|
||||
|
||||
## Architecture Deep Dive
|
||||
|
||||
This section explains how OPSX works under the hood and how it compares to the standard workflow.
|
||||
|
||||
### Philosophy: Phases vs Actions
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ STANDARD WORKFLOW │
|
||||
│ (Phase-Locked, All-or-Nothing) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ PLANNING │ ───► │ IMPLEMENTING │ ───► │ ARCHIVING │ │
|
||||
│ │ PHASE │ │ PHASE │ │ PHASE │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ /openspec:proposal /openspec:apply /openspec:archive │
|
||||
│ │
|
||||
│ • Creates ALL artifacts at once │
|
||||
│ • Can't go back to update specs during implementation │
|
||||
│ • Phase gates enforce linear progression │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ OPSX WORKFLOW │
|
||||
│ (Fluid Actions, Iterative) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────┐ │
|
||||
│ │ ACTIONS (not phases) │ │
|
||||
│ │ │ │
|
||||
│ │ new ◄──► continue ◄──► apply ◄──► sync │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ └──────────┴───────────┴──────────┘ │ │
|
||||
│ │ any order │ │
|
||||
│ └────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ • Create artifacts one at a time OR fast-forward │
|
||||
│ • Update specs/design/tasks during implementation │
|
||||
│ • Dependencies enable progress, phases don't exist │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Component Architecture
|
||||
|
||||
**Standard workflow** uses hardcoded templates in TypeScript:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ STANDARD WORKFLOW COMPONENTS │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Hardcoded Templates (TypeScript strings) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Configurators (18+ classes, one per editor) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Generated Command Files (.claude/commands/openspec/*.md) │
|
||||
│ │
|
||||
│ • Fixed structure, no artifact awareness │
|
||||
│ • Change requires code modification + rebuild │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**OPSX** uses external schemas and a dependency graph engine:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ OPSX COMPONENTS │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Schema Definitions (YAML) │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ name: spec-driven │ │
|
||||
│ │ artifacts: │ │
|
||||
│ │ - id: proposal │ │
|
||||
│ │ generates: proposal.md │ │
|
||||
│ │ requires: [] ◄── Dependencies │ │
|
||||
│ │ - id: specs │ │
|
||||
│ │ generates: specs/**/*.md ◄── Glob patterns │ │
|
||||
│ │ requires: [proposal] ◄── Enables after proposal │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Artifact Graph Engine │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ • Topological sort (dependency ordering) │ │
|
||||
│ │ • State detection (filesystem existence) │ │
|
||||
│ │ • Rich instruction generation (templates + context) │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Skill Files (.claude/skills/openspec-*/SKILL.md) │
|
||||
│ │
|
||||
│ • Cross-editor compatible (Claude Code, Cursor, Windsurf) │
|
||||
│ • Skills query CLI for structured data │
|
||||
│ • Fully customizable via schema files │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Dependency Graph Model
|
||||
|
||||
Artifacts form a directed acyclic graph (DAG). Dependencies are **enablers**, not gates:
|
||||
|
||||
```
|
||||
proposal
|
||||
(root node)
|
||||
│
|
||||
┌─────────────┴─────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
specs design
|
||||
(requires: (requires:
|
||||
proposal) proposal)
|
||||
│ │
|
||||
└─────────────┬─────────────┘
|
||||
│
|
||||
▼
|
||||
tasks
|
||||
(requires:
|
||||
specs, design)
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ APPLY PHASE │
|
||||
│ (requires: │
|
||||
│ tasks) │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
**State transitions:**
|
||||
|
||||
```
|
||||
BLOCKED ────────────────► READY ────────────────► DONE
|
||||
│ │ │
|
||||
Missing All deps File exists
|
||||
dependencies are DONE on filesystem
|
||||
```
|
||||
|
||||
### Information Flow
|
||||
|
||||
**Standard workflow** — agent receives static instructions:
|
||||
|
||||
```
|
||||
User: "/openspec:proposal"
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Static instructions: │
|
||||
│ • Create proposal.md │
|
||||
│ • Create tasks.md │
|
||||
│ • Create design.md │
|
||||
│ • Create specs/*.md │
|
||||
│ │
|
||||
│ No awareness of what exists or │
|
||||
│ dependencies between artifacts │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
Agent creates ALL artifacts in one go
|
||||
```
|
||||
|
||||
**OPSX** — agent queries for rich context:
|
||||
|
||||
```
|
||||
User: "/opsx:continue"
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ Step 1: Query current state │
|
||||
│ ┌────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ $ openspec status --change "add-auth" --json │ │
|
||||
│ │ │ │
|
||||
│ │ { │ │
|
||||
│ │ "artifacts": [ │ │
|
||||
│ │ {"id": "proposal", "status": "done"}, │ │
|
||||
│ │ {"id": "specs", "status": "ready"}, ◄── First ready │ │
|
||||
│ │ {"id": "design", "status": "ready"}, │ │
|
||||
│ │ {"id": "tasks", "status": "blocked", "missingDeps": ["specs"]}│ │
|
||||
│ │ ] │ │
|
||||
│ │ } │ │
|
||||
│ └────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Step 2: Get rich instructions for ready artifact │
|
||||
│ ┌────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ $ openspec instructions specs --change "add-auth" --json │ │
|
||||
│ │ │ │
|
||||
│ │ { │ │
|
||||
│ │ "template": "# Specification\n\n## ADDED Requirements...", │ │
|
||||
│ │ "dependencies": [{"id": "proposal", "path": "...", "done": true}│ │
|
||||
│ │ "unlocks": ["tasks"] │ │
|
||||
│ │ } │ │
|
||||
│ └────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Step 3: Read dependencies → Create ONE artifact → Show what's unlocked │
|
||||
└──────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Iteration Model
|
||||
|
||||
**Standard workflow** — awkward to iterate:
|
||||
|
||||
```
|
||||
┌─────────┐ ┌─────────┐ ┌─────────┐
|
||||
│/proposal│ ──► │ /apply │ ──► │/archive │
|
||||
└─────────┘ └─────────┘ └─────────┘
|
||||
│ │
|
||||
│ ├── "Wait, the design is wrong"
|
||||
│ │
|
||||
│ ├── Options:
|
||||
│ │ • Edit files manually (breaks context)
|
||||
│ │ • Abandon and start over
|
||||
│ │ • Push through and fix later
|
||||
│ │
|
||||
│ └── No official "go back" mechanism
|
||||
│
|
||||
└── Creates ALL artifacts at once
|
||||
```
|
||||
|
||||
**OPSX** — natural iteration:
|
||||
|
||||
```
|
||||
/opsx:new ───► /opsx:continue ───► /opsx:apply ───► /opsx:archive
|
||||
│ │ │
|
||||
│ │ ├── "The design is wrong"
|
||||
│ │ │
|
||||
│ │ ▼
|
||||
│ │ Just edit design.md
|
||||
│ │ and continue!
|
||||
│ │ │
|
||||
│ │ ▼
|
||||
│ │ /opsx:apply picks up
|
||||
│ │ where you left off
|
||||
│ │
|
||||
│ └── Creates ONE artifact, shows what's unlocked
|
||||
│
|
||||
└── Scaffolds change, waits for direction
|
||||
```
|
||||
|
||||
### Custom Schemas
|
||||
|
||||
Create custom workflows using the schema management commands:
|
||||
|
||||
```bash
|
||||
# Create a new schema from scratch (interactive)
|
||||
openspec schema init my-workflow
|
||||
|
||||
# Or fork an existing schema as a starting point
|
||||
openspec schema fork spec-driven my-workflow
|
||||
|
||||
# Validate your schema structure
|
||||
openspec schema validate my-workflow
|
||||
|
||||
# See where a schema resolves from (useful for debugging)
|
||||
openspec schema which my-workflow
|
||||
```
|
||||
|
||||
Schemas are stored in `openspec/schemas/` (project-local, version controlled) or `~/.local/share/openspec/schemas/` (user global).
|
||||
|
||||
**Schema structure:**
|
||||
```
|
||||
openspec/schemas/research-first/
|
||||
├── schema.yaml
|
||||
└── templates/
|
||||
├── research.md
|
||||
├── proposal.md
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
**Example schema.yaml:**
|
||||
```yaml
|
||||
name: research-first
|
||||
artifacts:
|
||||
- id: research # Added before proposal
|
||||
generates: research.md
|
||||
requires: []
|
||||
|
||||
- id: proposal
|
||||
generates: proposal.md
|
||||
requires: [research] # Now depends on research
|
||||
|
||||
- id: tasks
|
||||
generates: tasks.md
|
||||
requires: [proposal]
|
||||
```
|
||||
|
||||
**Dependency Graph:**
|
||||
```
|
||||
research ──► proposal ──► tasks
|
||||
```
|
||||
|
||||
### Summary
|
||||
|
||||
| Aspect | Standard | OPSX |
|
||||
|--------|----------|------|
|
||||
| **Templates** | Hardcoded TypeScript | External YAML + Markdown |
|
||||
| **Dependencies** | None (all at once) | DAG with topological sort |
|
||||
| **State** | Phase-based mental model | Filesystem existence |
|
||||
| **Customization** | Edit source, rebuild | Create schema.yaml |
|
||||
| **Iteration** | Phase-locked | Fluid, edit anything |
|
||||
| **Editor Support** | 18+ configurator classes | Single skills directory |
|
||||
|
||||
## Schemas
|
||||
|
||||
Schemas define what artifacts exist and their dependencies. Currently available:
|
||||
|
||||
- **spec-driven** (default): proposal → specs → design → tasks
|
||||
- **tdd**: tests → implementation → docs
|
||||
|
||||
```bash
|
||||
# List available schemas
|
||||
openspec schemas
|
||||
|
||||
# See all schemas with their resolution sources
|
||||
openspec schema which --all
|
||||
|
||||
# Create a new schema interactively
|
||||
openspec schema init my-workflow
|
||||
|
||||
# Fork an existing schema for customization
|
||||
openspec schema fork spec-driven my-workflow
|
||||
|
||||
# Validate schema structure before use
|
||||
openspec schema validate my-workflow
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
- Use `/opsx:explore` to think through an idea before committing to a change
|
||||
- `/opsx:ff` when you know what you want, `/opsx:continue` when exploring
|
||||
- During `/opsx:apply`, if something's wrong — fix the artifact, then continue
|
||||
- Tasks track progress via checkboxes in `tasks.md`
|
||||
- Check status anytime: `openspec status --change "name"`
|
||||
|
||||
## Feedback
|
||||
|
||||
This is rough. That's intentional — we're learning what works.
|
||||
|
||||
Found a bug? Have ideas? Join us on [Discord](https://discord.gg/YctCnvvshC) or open an issue on [GitHub](https://github.com/Fission-AI/openspec/issues).
|
||||
@@ -0,0 +1,205 @@
|
||||
# Project Config Demo Guide
|
||||
|
||||
A quick-reference guide for demonstrating the `openspec/config.yaml` feature.
|
||||
|
||||
## Summary: What Project Config Does
|
||||
|
||||
The feature adds `openspec/config.yaml` as a lightweight customization layer that lets teams:
|
||||
|
||||
- **Set a default schema** - New changes automatically use this schema instead of having to specify `--schema` every time
|
||||
- **Inject project context** - Shared context (tech stack, conventions) shown to AI when creating any artifact
|
||||
- **Add per-artifact rules** - Custom rules that only apply to specific artifacts (e.g., proposal, specs)
|
||||
|
||||
## Demo Walkthrough
|
||||
|
||||
### Demo 1: Interactive Setup (Recommended Entry Point)
|
||||
|
||||
The easiest way to demo is through the experimental setup command:
|
||||
|
||||
```bash
|
||||
openspec artifact-experimental-setup
|
||||
```
|
||||
|
||||
After creating skills/commands, it will prompt:
|
||||
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
📋 Project Configuration (Optional)
|
||||
|
||||
Configure project defaults for OpenSpec workflows.
|
||||
|
||||
? Create openspec/config.yaml? (Y/n)
|
||||
```
|
||||
|
||||
Walk through:
|
||||
|
||||
1. **Select schema** - Shows available schemas with their artifact flows
|
||||
2. **Add context** - Opens editor for multi-line project context (tech stack, conventions)
|
||||
3. **Add rules** - Checkbox to select artifacts, then line-by-line rule entry
|
||||
|
||||
This creates `openspec/config.yaml` with the user's choices.
|
||||
|
||||
### Demo 2: Manual Config Creation
|
||||
|
||||
Show that users can create the config directly:
|
||||
|
||||
```bash
|
||||
cat > openspec/config.yaml << 'EOF'
|
||||
schema: spec-driven
|
||||
|
||||
context: |
|
||||
Tech stack: TypeScript, React, Node.js, PostgreSQL
|
||||
API style: RESTful, documented in docs/api.md
|
||||
Testing: Jest + React Testing Library
|
||||
We value backwards compatibility for all public APIs
|
||||
|
||||
rules:
|
||||
proposal:
|
||||
- Include rollback plan
|
||||
- Identify affected teams and notify in #platform-changes
|
||||
specs:
|
||||
- Use Given/When/Then format
|
||||
- Reference existing patterns before inventing new ones
|
||||
EOF
|
||||
```
|
||||
|
||||
### Demo 3: Effect on New Changes
|
||||
|
||||
Show that creating a new change now uses the default schema:
|
||||
|
||||
```bash
|
||||
# Before config: had to specify schema
|
||||
openspec new change my-feature --schema spec-driven
|
||||
|
||||
# After config: schema is automatic
|
||||
openspec new change my-feature
|
||||
# Automatically uses spec-driven from config
|
||||
```
|
||||
|
||||
### Demo 4: Context and Rules Injection
|
||||
|
||||
The key demo moment - show how instructions are enriched:
|
||||
|
||||
```bash
|
||||
# Get instructions for an artifact
|
||||
openspec instructions proposal --change my-feature
|
||||
```
|
||||
|
||||
Output shows the XML structure:
|
||||
|
||||
```xml
|
||||
<context>
|
||||
Tech stack: TypeScript, React, Node.js, PostgreSQL
|
||||
API style: RESTful, documented in docs/api.md
|
||||
...
|
||||
</context>
|
||||
|
||||
<rules>
|
||||
- Include rollback plan
|
||||
- Identify affected teams and notify in #platform-changes
|
||||
</rules>
|
||||
|
||||
<template>
|
||||
[Schema's built-in proposal template]
|
||||
</template>
|
||||
```
|
||||
|
||||
Key points to highlight:
|
||||
|
||||
- **Context** appears in ALL artifacts (proposal, specs, design, tasks)
|
||||
- **Rules** ONLY appear for the matching artifact (proposal rules only in proposal instructions)
|
||||
|
||||
### Demo 5: Precedence Override
|
||||
|
||||
Show the schema resolution order:
|
||||
|
||||
```bash
|
||||
# Config sets schema: spec-driven
|
||||
|
||||
# 1. CLI flag wins
|
||||
openspec new change feature-a --schema tdd # Uses tdd
|
||||
|
||||
# 2. Change metadata wins over config
|
||||
# (if .openspec.yaml in change directory specifies schema)
|
||||
|
||||
# 3. Config is used as default
|
||||
openspec new change feature-b # Uses spec-driven from config
|
||||
|
||||
# 4. Hardcoded default (no config)
|
||||
# Would fall back to spec-driven anyway
|
||||
```
|
||||
|
||||
### Demo 6: Validation and Error Handling
|
||||
|
||||
Show graceful error handling:
|
||||
|
||||
```bash
|
||||
# Create config with typo
|
||||
echo "schema: spec-drivne" > openspec/config.yaml
|
||||
|
||||
# Try to use it - shows fuzzy matching suggestions
|
||||
openspec new change test
|
||||
# Schema 'spec-drivne' not found
|
||||
# Did you mean: spec-driven (built-in)
|
||||
```
|
||||
|
||||
```bash
|
||||
# Unknown artifact ID in rules - warns but doesn't halt
|
||||
cat > openspec/config.yaml << 'EOF'
|
||||
schema: spec-driven
|
||||
rules:
|
||||
testplan: # Schema doesn't have this
|
||||
- Some rule
|
||||
EOF
|
||||
|
||||
openspec instructions proposal --change test
|
||||
# ⚠️ Unknown artifact ID in rules: "testplan". Valid IDs for schema "spec-driven": ...
|
||||
# (continues working)
|
||||
```
|
||||
|
||||
## Quick Demo Script
|
||||
|
||||
Here's a quick all-in-one demo:
|
||||
|
||||
```bash
|
||||
# 1. Show there's no config initially
|
||||
cat openspec/config.yaml 2>/dev/null || echo "No config exists"
|
||||
|
||||
# 2. Create a simple config
|
||||
cat > openspec/config.yaml << 'EOF'
|
||||
schema: spec-driven
|
||||
context: |
|
||||
This is a demo project using React and TypeScript.
|
||||
We follow semantic versioning.
|
||||
rules:
|
||||
proposal:
|
||||
- Include migration steps if breaking change
|
||||
EOF
|
||||
|
||||
# 3. Show the config
|
||||
cat openspec/config.yaml
|
||||
|
||||
# 4. Create a change (uses default schema from config)
|
||||
openspec new change demo-feature
|
||||
|
||||
# 5. Show instructions with injected context/rules
|
||||
openspec instructions proposal --change demo-feature | head -30
|
||||
|
||||
# 6. Show that specs don't have proposal rules
|
||||
openspec instructions specs --change demo-feature | head -30
|
||||
```
|
||||
|
||||
## What to Emphasize in Demo
|
||||
|
||||
- **Low friction** - Teams can customize without forking schemas
|
||||
- **Shared context** - Everyone on the team gets the same project knowledge
|
||||
- **Per-artifact rules** - Targeted guidance where it matters
|
||||
- **Graceful failures** - Typos warn, don't break workflow
|
||||
- **Team sharing** - Just commit `openspec/config.yaml` and everyone benefits
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Experimental Workflow Guide](./experimental-workflow.md) - Full user guide with config section
|
||||
- [Project Config Proposal](../openspec/changes/project-config/proposal.md) - Original design proposal
|
||||
- [Project Config Design](../openspec/changes/project-config/design.md) - Technical implementation details
|
||||
@@ -0,0 +1,211 @@
|
||||
# Schema Customization
|
||||
|
||||
This document describes how users can customize OpenSpec schemas and templates, the current manual process, and the gap that needs to be addressed.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
OpenSpec uses a 2-level schema resolution system following the XDG Base Directory Specification:
|
||||
|
||||
1. **User override**: `${XDG_DATA_HOME}/openspec/schemas/<name>/`
|
||||
2. **Package built-in**: `<npm-package>/schemas/<name>/`
|
||||
|
||||
When a schema is requested (e.g., `spec-driven`), the resolver checks the user directory first. If found, that entire schema directory is used. Otherwise, it falls back to the package's built-in schema.
|
||||
|
||||
---
|
||||
|
||||
## Current Manual Process
|
||||
|
||||
To override the default `spec-driven` schema, a user must:
|
||||
|
||||
### 1. Determine the correct directory path
|
||||
|
||||
| Platform | Path |
|
||||
|----------|------|
|
||||
| macOS/Linux | `~/.local/share/openspec/schemas/` |
|
||||
| Windows | `%LOCALAPPDATA%\openspec\schemas\` |
|
||||
| All (if set) | `$XDG_DATA_HOME/openspec/schemas/` |
|
||||
|
||||
### 2. Create the directory structure
|
||||
|
||||
```bash
|
||||
# macOS/Linux example
|
||||
mkdir -p ~/.local/share/openspec/schemas/spec-driven/templates
|
||||
```
|
||||
|
||||
### 3. Find and copy the default schema files
|
||||
|
||||
The user must locate the installed npm package to copy the defaults:
|
||||
|
||||
```bash
|
||||
# Find the package location (varies by install method)
|
||||
npm list -g openspec --parseable
|
||||
# or
|
||||
which openspec && readlink -f $(which openspec)
|
||||
|
||||
# Copy files from the package's schemas/ directory
|
||||
cp <package-path>/schemas/spec-driven/schema.yaml ~/.local/share/openspec/schemas/spec-driven/
|
||||
cp <package-path>/schemas/spec-driven/templates/*.md ~/.local/share/openspec/schemas/spec-driven/templates/
|
||||
```
|
||||
|
||||
### 4. Modify the copied files
|
||||
|
||||
Edit `schema.yaml` to change the workflow structure:
|
||||
|
||||
```yaml
|
||||
name: spec-driven
|
||||
version: 1
|
||||
description: My custom workflow
|
||||
artifacts:
|
||||
- id: proposal
|
||||
generates: proposal.md
|
||||
description: Initial proposal
|
||||
template: proposal.md
|
||||
requires: []
|
||||
# Add, remove, or modify artifacts...
|
||||
```
|
||||
|
||||
Edit templates in `templates/` to customize the content guidance.
|
||||
|
||||
### 5. Verify the override is active
|
||||
|
||||
Currently there's no command to verify which schema is being used. Users must trust that the file exists in the right location.
|
||||
|
||||
---
|
||||
|
||||
## Gap Analysis
|
||||
|
||||
The current process has several friction points:
|
||||
|
||||
| Issue | Impact |
|
||||
|-------|--------|
|
||||
| **Path discovery** | Users must know XDG conventions and platform-specific paths |
|
||||
| **Package location** | Finding the npm package path varies by install method (global, local, pnpm, yarn, volta, etc.) |
|
||||
| **No scaffolding** | Users must manually create directories and copy files |
|
||||
| **No verification** | No way to confirm which schema is actually being resolved |
|
||||
| **No diffing** | When upgrading openspec, users can't see what changed in built-in templates |
|
||||
| **Full copy required** | Must copy entire schema even to change one template |
|
||||
|
||||
### User Stories Not Currently Supported
|
||||
|
||||
1. *"I want to add a `research` artifact before `proposal`"* — requires manual copy and edit
|
||||
2. *"I want to customize just the proposal template"* — must copy entire schema
|
||||
3. *"I want to see what the default schema looks like"* — must find package path
|
||||
4. *"I want to revert to defaults"* — must delete files and hope paths are correct
|
||||
5. *"I upgraded openspec, did the templates change?"* — no way to diff
|
||||
|
||||
---
|
||||
|
||||
## Proposed Solution: Schema Configurator
|
||||
|
||||
A CLI command (or set of commands) that handles path resolution and file operations for users.
|
||||
|
||||
### Option A: Single `openspec schema` command
|
||||
|
||||
```bash
|
||||
# List available schemas (built-in and user overrides)
|
||||
openspec schema list
|
||||
|
||||
# Show where a schema resolves from
|
||||
openspec schema which spec-driven
|
||||
# Output: /Users/me/.local/share/openspec/schemas/spec-driven/ (user override)
|
||||
# Output: /usr/local/lib/node_modules/openspec/schemas/spec-driven/ (built-in)
|
||||
|
||||
# Copy a built-in schema to user directory for customization
|
||||
openspec schema copy spec-driven
|
||||
# Creates ~/.local/share/openspec/schemas/spec-driven/ with all files
|
||||
|
||||
# Show diff between user override and built-in
|
||||
openspec schema diff spec-driven
|
||||
|
||||
# Remove user override (revert to built-in)
|
||||
openspec schema reset spec-driven
|
||||
|
||||
# Validate a schema
|
||||
openspec schema validate spec-driven
|
||||
```
|
||||
|
||||
### Option B: Dedicated `openspec customize` command
|
||||
|
||||
```bash
|
||||
# Interactive schema customization
|
||||
openspec customize
|
||||
# Prompts: Which schema? What do you want to change? etc.
|
||||
|
||||
# Copy and open for editing
|
||||
openspec customize spec-driven
|
||||
# Copies to user dir, prints path, optionally opens in $EDITOR
|
||||
```
|
||||
|
||||
### Option C: Init-time schema selection
|
||||
|
||||
```bash
|
||||
# During project init, offer schema customization
|
||||
openspec init
|
||||
# ? Select a workflow schema:
|
||||
# > spec-driven (default)
|
||||
# tdd
|
||||
# minimal
|
||||
# custom (copy and edit)
|
||||
```
|
||||
|
||||
### Recommended Approach
|
||||
|
||||
**Option A** provides the most flexibility and follows Unix conventions (subcommands for discrete operations). Key commands in priority order:
|
||||
|
||||
1. `openspec schema list` — see what's available
|
||||
2. `openspec schema which <name>` — debug resolution
|
||||
3. `openspec schema copy <name>` — scaffold customization
|
||||
4. `openspec schema diff <name>` — compare with built-in
|
||||
5. `openspec schema reset <name>` — revert to defaults
|
||||
|
||||
---
|
||||
|
||||
## Implementation Considerations
|
||||
|
||||
### Path Resolution
|
||||
|
||||
The resolver already exists in `src/core/artifact-graph/resolver.ts`:
|
||||
|
||||
```typescript
|
||||
export function getPackageSchemasDir(): string { ... }
|
||||
export function getUserSchemasDir(): string { ... }
|
||||
export function getSchemaDir(name: string): string | null { ... }
|
||||
export function listSchemas(): string[] { ... }
|
||||
```
|
||||
|
||||
New commands would leverage these existing functions.
|
||||
|
||||
### File Operations
|
||||
|
||||
- Copy should preserve file permissions
|
||||
- Copy should not overwrite existing user files without `--force`
|
||||
- Reset should prompt for confirmation
|
||||
|
||||
### Template-Only Overrides
|
||||
|
||||
A future enhancement could support overriding individual templates without copying the entire schema. This would require changes to the resolution logic:
|
||||
|
||||
```
|
||||
Current: schema dir (user) OR schema dir (built-in)
|
||||
Future: schema.yaml from user OR built-in
|
||||
+ each template from user OR built-in (independent fallback)
|
||||
```
|
||||
|
||||
This adds complexity but enables the "I just want to change one template" use case.
|
||||
|
||||
---
|
||||
|
||||
## Related Documents
|
||||
|
||||
- [Schema Workflow Gaps](./schema-workflow-gaps.md) — End-to-end workflow analysis and phased implementation plan
|
||||
|
||||
## Related Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `src/core/artifact-graph/resolver.ts` | Schema resolution logic |
|
||||
| `src/core/artifact-graph/instruction-loader.ts` | Template loading |
|
||||
| `src/core/global-config.ts` | XDG path helpers |
|
||||
| `schemas/spec-driven/` | Default schema and templates |
|
||||
@@ -0,0 +1,379 @@
|
||||
# Schema Workflow: End-to-End Analysis
|
||||
|
||||
This document analyzes the complete user journey for working with schemas in OpenSpec, identifies gaps, and proposes a phased solution.
|
||||
|
||||
---
|
||||
|
||||
## Current State
|
||||
|
||||
### What Exists
|
||||
|
||||
| Component | Status |
|
||||
|-----------|--------|
|
||||
| Schema resolution | 3-level: project → user → package (PR #522) |
|
||||
| Built-in schemas | `spec-driven`, `tdd` |
|
||||
| Artifact workflow commands | `status`, `next`, `instructions`, `templates` with `--schema` flag |
|
||||
| Change creation | `openspec new change <name>` — no schema binding |
|
||||
| Project-local schemas | ✅ Supported via `openspec/schemas/` (PR #522) |
|
||||
| Schema management CLI | ✅ `schema which`, `validate`, `fork`, `init` (PR #525) |
|
||||
|
||||
### What's Missing
|
||||
|
||||
| Component | Status |
|
||||
|-----------|--------|
|
||||
| Schema bound to change | Not stored — must pass `--schema` every time |
|
||||
| Project default schema | None — hardcoded to `spec-driven` |
|
||||
|
||||
---
|
||||
|
||||
## User Journey Analysis
|
||||
|
||||
### Scenario 1: Using a Non-Default Schema
|
||||
|
||||
**Goal:** User wants to use TDD workflow for a new feature.
|
||||
|
||||
**Today's experience:**
|
||||
```bash
|
||||
openspec new change add-auth
|
||||
# Creates directory, no schema info stored
|
||||
|
||||
openspec status --change add-auth
|
||||
# Shows spec-driven artifacts (WRONG - user wanted TDD)
|
||||
|
||||
# User realizes mistake...
|
||||
openspec status --change add-auth --schema tdd
|
||||
# Correct, but must remember --schema every time
|
||||
|
||||
# 6 months later...
|
||||
openspec status --change add-auth
|
||||
# Wrong again - nobody remembers this was TDD
|
||||
```
|
||||
|
||||
**Problems:**
|
||||
- Schema is a runtime argument, not persisted
|
||||
- Easy to forget `--schema` and get wrong results
|
||||
- No record of intended schema for future reference
|
||||
|
||||
---
|
||||
|
||||
### Scenario 2: Customizing a Schema
|
||||
|
||||
**Goal:** User wants to add a "research" artifact before "proposal".
|
||||
|
||||
**Today's experience:**
|
||||
```bash
|
||||
# Step 1: Figure out where to put overrides
|
||||
# Must know XDG conventions:
|
||||
# macOS/Linux: ~/.local/share/openspec/schemas/
|
||||
# Windows: %LOCALAPPDATA%\openspec\schemas/
|
||||
|
||||
# Step 2: Create directory structure
|
||||
mkdir -p ~/.local/share/openspec/schemas/my-workflow/templates
|
||||
|
||||
# Step 3: Find the npm package to copy defaults
|
||||
npm list -g openspec --parseable
|
||||
# Output varies by package manager:
|
||||
# npm: /usr/local/lib/node_modules/openspec
|
||||
# pnpm: ~/.local/share/pnpm/global/5/node_modules/openspec
|
||||
# volta: ~/.volta/tools/image/packages/openspec/...
|
||||
# yarn: ~/.config/yarn/global/node_modules/openspec
|
||||
|
||||
# Step 4: Copy files
|
||||
cp -r <package-path>/schemas/spec-driven/* \
|
||||
~/.local/share/openspec/schemas/my-workflow/
|
||||
|
||||
# Step 5: Edit schema.yaml and templates
|
||||
# No way to verify override is active
|
||||
# No way to diff against original
|
||||
```
|
||||
|
||||
**Problems:**
|
||||
- Must know XDG path conventions
|
||||
- Finding npm package path varies by install method
|
||||
- No tooling to scaffold or verify
|
||||
- No diff capability when upgrading openspec
|
||||
|
||||
---
|
||||
|
||||
### Scenario 3: Team Sharing Custom Workflow
|
||||
|
||||
**Goal:** Team wants everyone to use the same custom schema.
|
||||
|
||||
**Today's options:**
|
||||
1. Everyone manually sets up XDG override — error-prone, drift risk
|
||||
2. Document setup in README — still manual, easy to miss
|
||||
3. Publish separate npm package — overkill for most teams
|
||||
4. Check schema into repo — **not supported** (no project-local resolution)
|
||||
|
||||
**Problems:**
|
||||
- No project-local schema resolution
|
||||
- Can't version control custom schemas with the codebase
|
||||
- No single source of truth for team workflow
|
||||
|
||||
---
|
||||
|
||||
## Gap Summary
|
||||
|
||||
| Gap | Impact | Status |
|
||||
|-----|--------|--------|
|
||||
| Schema not bound to change | Wrong results, forgotten context | ⏳ Pending (Phase 1) |
|
||||
| No project-local schemas | Can't share via repo | ✅ Fixed (PR #522) |
|
||||
| No schema management CLI | Manual path hunting | ✅ Fixed (PR #525) |
|
||||
| No project default schema | Must specify every time | ⏳ Pending (Phase 4) |
|
||||
| No init-time schema selection | Missed setup opportunity | ⏳ Pending (Phase 4) |
|
||||
|
||||
---
|
||||
|
||||
## Proposed Architecture
|
||||
|
||||
### New File Structure
|
||||
|
||||
```
|
||||
openspec/
|
||||
├── config.yaml # Project config (NEW)
|
||||
├── schemas/ # Project-local schemas (NEW)
|
||||
│ └── my-workflow/
|
||||
│ ├── schema.yaml
|
||||
│ └── templates/
|
||||
│ ├── research.md
|
||||
│ ├── proposal.md
|
||||
│ └── ...
|
||||
└── changes/
|
||||
└── add-auth/
|
||||
├── change.yaml # Change metadata (NEW)
|
||||
├── proposal.md
|
||||
└── ...
|
||||
```
|
||||
|
||||
### config.yaml (Project Config)
|
||||
|
||||
```yaml
|
||||
# openspec/config.yaml
|
||||
defaultSchema: spec-driven
|
||||
```
|
||||
|
||||
Sets the project-wide default schema. Used when:
|
||||
- Creating new changes without `--schema`
|
||||
- Running commands on changes without `change.yaml`
|
||||
|
||||
### change.yaml (Change Metadata)
|
||||
|
||||
```yaml
|
||||
# openspec/changes/add-auth/change.yaml
|
||||
schema: tdd
|
||||
created: 2025-01-15T10:30:00Z
|
||||
description: Add user authentication system
|
||||
```
|
||||
|
||||
Binds a specific schema to a change. Created automatically by `openspec new change`.
|
||||
|
||||
### Schema Resolution Order
|
||||
|
||||
```
|
||||
1. ./openspec/schemas/<name>/ # Project-local
|
||||
2. ~/.local/share/openspec/schemas/<name>/ # User global (XDG)
|
||||
3. <npm-package>/schemas/<name>/ # Built-in
|
||||
```
|
||||
|
||||
Project-local takes priority, enabling version-controlled custom schemas.
|
||||
|
||||
### Schema Selection Order (Per Command)
|
||||
|
||||
```
|
||||
1. --schema CLI flag # Explicit override
|
||||
2. change.yaml in change directory # Change-specific binding
|
||||
3. openspec/config.yaml defaultSchema # Project default
|
||||
4. "spec-driven" # Hardcoded fallback
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ideal User Experience
|
||||
|
||||
### Creating a Change
|
||||
|
||||
```bash
|
||||
# Uses project default (from config.yaml, or spec-driven)
|
||||
openspec new change add-auth
|
||||
# Creates openspec/changes/add-auth/change.yaml:
|
||||
# schema: spec-driven
|
||||
# created: 2025-01-15T10:30:00Z
|
||||
|
||||
# Explicit schema for this change
|
||||
openspec new change add-auth --schema tdd
|
||||
# Creates change.yaml with schema: tdd
|
||||
```
|
||||
|
||||
### Working with Changes
|
||||
|
||||
```bash
|
||||
# Auto-reads schema from change.yaml — no --schema needed
|
||||
openspec status --change add-auth
|
||||
# Output: "Change: add-auth (schema: tdd)"
|
||||
# Shows which artifacts are ready/blocked/done
|
||||
|
||||
# Explicit override still works (with informational message)
|
||||
openspec status --change add-auth --schema spec-driven
|
||||
# "Note: change.yaml specifies 'tdd', using 'spec-driven' per --schema flag"
|
||||
```
|
||||
|
||||
### Customizing Schemas
|
||||
|
||||
```bash
|
||||
# See what's available
|
||||
openspec schema list
|
||||
# Built-in:
|
||||
# spec-driven proposal → specs → design → tasks
|
||||
# tdd spec → tests → implementation → docs
|
||||
# Project: (none)
|
||||
# User: (none)
|
||||
|
||||
# Copy to project for customization
|
||||
openspec schema copy spec-driven my-workflow
|
||||
# Created ./openspec/schemas/my-workflow/
|
||||
# Edit schema.yaml and templates/ to customize
|
||||
|
||||
# Copy to global (user-level override)
|
||||
openspec schema copy spec-driven --global
|
||||
# Created ~/.local/share/openspec/schemas/spec-driven/
|
||||
|
||||
# See where a schema resolves from
|
||||
openspec schema which spec-driven
|
||||
# ./openspec/schemas/spec-driven/ (project)
|
||||
# or: ~/.local/share/openspec/schemas/spec-driven/ (user)
|
||||
# or: /usr/local/lib/node_modules/openspec/schemas/spec-driven/ (built-in)
|
||||
|
||||
# Compare override with built-in
|
||||
openspec schema diff spec-driven
|
||||
# Shows diff between user/project version and package built-in
|
||||
|
||||
# Remove override, revert to built-in
|
||||
openspec schema reset spec-driven
|
||||
# Removes ./openspec/schemas/spec-driven/ (or --global for user dir)
|
||||
```
|
||||
|
||||
### Project Setup
|
||||
|
||||
```bash
|
||||
openspec init
|
||||
# ? Select default workflow schema:
|
||||
# > spec-driven (proposal → specs → design → tasks)
|
||||
# tdd (spec → tests → implementation → docs)
|
||||
# (custom schemas if detected)
|
||||
#
|
||||
# Writes to openspec/config.yaml:
|
||||
# defaultSchema: spec-driven
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Change Metadata (change.yaml)
|
||||
|
||||
**Priority:** High
|
||||
**Solves:** "Forgot --schema", lost context, wrong results
|
||||
|
||||
**Scope:**
|
||||
- Create `change.yaml` when running `openspec new change`
|
||||
- Store `schema`, `created` timestamp
|
||||
- Modify workflow commands to read schema from `change.yaml`
|
||||
- `--schema` flag overrides (with informational message)
|
||||
- Backwards compatible: missing `change.yaml` → use default
|
||||
|
||||
**change.yaml format:**
|
||||
```yaml
|
||||
schema: tdd
|
||||
created: 2025-01-15T10:30:00Z
|
||||
```
|
||||
|
||||
**Migration:**
|
||||
- Existing changes without `change.yaml` continue to work
|
||||
- Default to `spec-driven` (current behavior)
|
||||
- Optional: `openspec migrate` to add `change.yaml` to existing changes
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Project-Local Schemas
|
||||
|
||||
**Status:** ✅ Complete (PR #522)
|
||||
**Solves:** Team sharing, version control, no XDG knowledge needed
|
||||
|
||||
**Implemented:**
|
||||
- `./openspec/schemas/` added to resolution order (first priority)
|
||||
- `openspec schema fork <name> [new-name]` creates in project by default
|
||||
- Teams can commit `openspec/schemas/` to repo
|
||||
|
||||
**Resolution order:**
|
||||
```
|
||||
1. ./openspec/schemas/<name>/ # Project-local
|
||||
2. ~/.local/share/openspec/schemas/<name>/ # User global
|
||||
3. <npm-package>/schemas/<name>/ # Built-in
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Schema Management CLI
|
||||
|
||||
**Status:** ✅ Complete (PR #525)
|
||||
**Solves:** Path discovery, scaffolding, debugging
|
||||
|
||||
**Implemented Commands:**
|
||||
```bash
|
||||
openspec schema which [name] # Show resolution path, --all for all schemas
|
||||
openspec schema validate [name] # Validate schema structure and templates
|
||||
openspec schema fork <source> [name] # Copy existing schema for customization
|
||||
openspec schema init <name> # Create new project-local schema (interactive)
|
||||
```
|
||||
|
||||
**Not implemented (may add later):**
|
||||
- `schema diff` — Compare override with built-in
|
||||
- `schema reset` — Remove override, revert to built-in
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: Project Config + Init Enhancement
|
||||
|
||||
**Priority:** Low
|
||||
**Solves:** Project-wide defaults, streamlined setup
|
||||
|
||||
**Scope:**
|
||||
- Add `openspec/config.yaml` with `defaultSchema` field
|
||||
- `openspec init` prompts for schema selection
|
||||
- Store selection in `config.yaml`
|
||||
- Commands use as fallback when no `change.yaml` exists
|
||||
|
||||
**config.yaml format:**
|
||||
```yaml
|
||||
defaultSchema: spec-driven
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backwards Compatibility
|
||||
|
||||
| Scenario | Behavior |
|
||||
|----------|----------|
|
||||
| Existing change without `change.yaml` | Uses `--schema` flag or project default or `spec-driven` |
|
||||
| Existing project without `config.yaml` | Falls back to `spec-driven` |
|
||||
| `--schema` flag provided | Overrides `change.yaml` (with info message) |
|
||||
| No project-local schemas dir | Skipped in resolution, checks user/built-in |
|
||||
|
||||
All existing functionality continues to work. New features are additive.
|
||||
|
||||
---
|
||||
|
||||
## Related Documents
|
||||
|
||||
- [Schema Customization](./schema-customization.md) — Details on manual override process and CLI gaps
|
||||
- [Artifact POC](./artifact_poc.md) — Core artifact graph architecture
|
||||
|
||||
## Related Code
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `src/core/artifact-graph/resolver.ts` | Schema resolution logic |
|
||||
| `src/core/artifact-graph/instruction-loader.ts` | Template loading |
|
||||
| `src/core/global-config.ts` | XDG path helpers |
|
||||
| `src/commands/artifact-workflow.ts` | CLI commands |
|
||||
| `src/utils/change-utils.ts` | Change creation utilities |
|
||||
Generated
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1767640445,
|
||||
"narHash": "sha256-UWYqmD7JFBEDBHWYcqE6s6c77pWdcU/i+bwD6XxMb8A=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9f0c42f8bc7151b8e7e5840fb3bd454ad850d8c5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
{
|
||||
description = "OpenSpec - AI-native system for spec-driven development";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs }:
|
||||
let
|
||||
supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
|
||||
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system);
|
||||
in
|
||||
{
|
||||
packages = forAllSystems (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
default = pkgs.stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "openspec";
|
||||
version = "0.23.0";
|
||||
|
||||
src = ./.;
|
||||
|
||||
pnpmDeps = pkgs.fetchPnpmDeps {
|
||||
inherit (finalAttrs) pname version src;
|
||||
pnpm = pkgs.pnpm_9;
|
||||
fetcherVersion = 3;
|
||||
hash = "sha256-9s2kdvd7svK4hofnD66HkDc86WTQeayfF5y7L2dmjNg=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
nodejs_20
|
||||
npmHooks.npmInstallHook
|
||||
pnpmConfigHook
|
||||
pnpm_9
|
||||
];
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
pnpm run build
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
dontNpmPrune = true;
|
||||
|
||||
meta = with pkgs.lib; {
|
||||
description = "AI-native system for spec-driven development";
|
||||
homepage = "https://github.com/Fission-AI/OpenSpec";
|
||||
license = licenses.mit;
|
||||
maintainers = [ ];
|
||||
mainProgram = "openspec";
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
apps = forAllSystems (system: {
|
||||
default = {
|
||||
type = "app";
|
||||
program = "${self.packages.${system}.default}/bin/openspec";
|
||||
};
|
||||
});
|
||||
|
||||
devShells = forAllSystems (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
nodejs_20
|
||||
pnpm_9
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
echo "OpenSpec development environment"
|
||||
echo "Node version: $(node --version)"
|
||||
echo "pnpm version: $(pnpm --version)"
|
||||
echo "Run 'pnpm install' to install dependencies"
|
||||
'';
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1,454 +0,0 @@
|
||||
# OpenSpec Instructions
|
||||
|
||||
Instructions for AI coding assistants using OpenSpec for spec-driven development.
|
||||
|
||||
## TL;DR Quick Checklist
|
||||
|
||||
- Search existing work: `openspec spec list --long`, `openspec list` (use `rg` only for full-text search)
|
||||
- Decide scope: new capability vs modify existing capability
|
||||
- Pick a unique `change-id`: kebab-case, verb-led (`add-`, `update-`, `remove-`, `refactor-`)
|
||||
- Scaffold: `proposal.md`, `tasks.md`, `design.md` (only if needed), and delta specs per affected capability
|
||||
- Write deltas: use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements`; include at least one `#### Scenario:` per requirement
|
||||
- Validate: `openspec validate [change-id] --strict` and fix issues
|
||||
- Request approval: Do not start implementation until proposal is approved
|
||||
|
||||
## Three-Stage Workflow
|
||||
|
||||
### Stage 1: Creating Changes
|
||||
Create proposal when you need to:
|
||||
- Add features or functionality
|
||||
- Make breaking changes (API, schema)
|
||||
- Change architecture or patterns
|
||||
- Optimize performance (changes behavior)
|
||||
- Update security patterns
|
||||
|
||||
Triggers (examples):
|
||||
- "Help me create a change proposal"
|
||||
- "Help me plan a change"
|
||||
- "Help me create a proposal"
|
||||
- "I want to create a spec proposal"
|
||||
- "I want to create a spec"
|
||||
|
||||
Loose matching guidance:
|
||||
- Contains one of: `proposal`, `change`, `spec`
|
||||
- With one of: `create`, `plan`, `make`, `start`, `help`
|
||||
|
||||
Skip proposal for:
|
||||
- Bug fixes (restore intended behavior)
|
||||
- Typos, formatting, comments
|
||||
- Dependency updates (non-breaking)
|
||||
- Configuration changes
|
||||
- Tests for existing behavior
|
||||
|
||||
**Workflow**
|
||||
1. Review `openspec/project.md`, `openspec list`, and `openspec list --specs` to understand current context.
|
||||
2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, optional `design.md`, and spec deltas under `openspec/changes/<id>/`.
|
||||
3. Draft spec deltas using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement.
|
||||
4. Run `openspec validate <id> --strict` and resolve any issues before sharing the proposal.
|
||||
|
||||
### Stage 2: Implementing Changes
|
||||
Track these steps as TODOs and complete them one by one.
|
||||
1. **Read proposal.md** - Understand what's being built
|
||||
2. **Read design.md** (if exists) - Review technical decisions
|
||||
3. **Read tasks.md** - Get implementation checklist
|
||||
4. **Implement tasks sequentially** - Complete in order
|
||||
5. **Confirm completion** - Ensure every item in `tasks.md` is finished before updating statuses
|
||||
6. **Update checklist** - After all work is done, set every task to `- [x]` so the list reflects reality
|
||||
7. **Approval gate** - Do not start implementation until the proposal is reviewed and approved
|
||||
|
||||
### Stage 3: Archiving Changes
|
||||
After deployment, create separate PR to:
|
||||
- Move `changes/[name]/` → `changes/archive/YYYY-MM-DD-[name]/`
|
||||
- Update `specs/` if capabilities changed
|
||||
- Use `openspec archive <change-id> --skip-specs --yes` for tooling-only changes (always pass the change ID explicitly)
|
||||
- Run `openspec validate --strict` to confirm the archived change passes checks
|
||||
|
||||
## Before Any Task
|
||||
|
||||
**Context Checklist:**
|
||||
- [ ] Read relevant specs in `specs/[capability]/spec.md`
|
||||
- [ ] Check pending changes in `changes/` for conflicts
|
||||
- [ ] Read `openspec/project.md` for conventions
|
||||
- [ ] Run `openspec list` to see active changes
|
||||
- [ ] Run `openspec list --specs` to see existing capabilities
|
||||
|
||||
**Before Creating Specs:**
|
||||
- Always check if capability already exists
|
||||
- Prefer modifying existing specs over creating duplicates
|
||||
- Use `openspec show [spec]` to review current state
|
||||
- If request is ambiguous, ask 1–2 clarifying questions before scaffolding
|
||||
|
||||
### Search Guidance
|
||||
- Enumerate specs: `openspec spec list --long` (or `--json` for scripts)
|
||||
- Enumerate changes: `openspec list` (or `openspec change list --json` - deprecated but available)
|
||||
- Show details:
|
||||
- Spec: `openspec show <spec-id> --type spec` (use `--json` for filters)
|
||||
- Change: `openspec show <change-id> --json --deltas-only`
|
||||
- Full-text search (use ripgrep): `rg -n "Requirement:|Scenario:" openspec/specs`
|
||||
|
||||
## Quick Start
|
||||
|
||||
### CLI Commands
|
||||
|
||||
```bash
|
||||
# Essential commands
|
||||
openspec list # List active changes
|
||||
openspec list --specs # List specifications
|
||||
openspec show [item] # Display change or spec
|
||||
openspec validate [item] # Validate changes or specs
|
||||
openspec archive <change-id> [--yes|-y] # Archive after deployment (add --yes for non-interactive runs)
|
||||
|
||||
# Project management
|
||||
openspec init [path] # Initialize OpenSpec
|
||||
openspec update [path] # Update instruction files
|
||||
|
||||
# Interactive mode
|
||||
openspec show # Prompts for selection
|
||||
openspec validate # Bulk validation mode
|
||||
|
||||
# Debugging
|
||||
openspec show [change] --json --deltas-only
|
||||
openspec validate [change] --strict
|
||||
```
|
||||
|
||||
### Command Flags
|
||||
|
||||
- `--json` - Machine-readable output
|
||||
- `--type change|spec` - Disambiguate items
|
||||
- `--strict` - Comprehensive validation
|
||||
- `--no-interactive` - Disable prompts
|
||||
- `--skip-specs` - Archive without spec updates
|
||||
- `--yes`/`-y` - Skip confirmation prompts (non-interactive archive)
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
openspec/
|
||||
├── project.md # Project conventions
|
||||
├── specs/ # Current truth - what IS built
|
||||
│ └── [capability]/ # Single focused capability
|
||||
│ ├── spec.md # Requirements and scenarios
|
||||
│ └── design.md # Technical patterns
|
||||
├── changes/ # Proposals - what SHOULD change
|
||||
│ ├── [change-name]/
|
||||
│ │ ├── proposal.md # Why, what, impact
|
||||
│ │ ├── tasks.md # Implementation checklist
|
||||
│ │ ├── design.md # Technical decisions (optional; see criteria)
|
||||
│ │ └── specs/ # Delta changes
|
||||
│ │ └── [capability]/
|
||||
│ │ └── spec.md # ADDED/MODIFIED/REMOVED
|
||||
│ └── archive/ # Completed changes
|
||||
```
|
||||
|
||||
## Creating Change Proposals
|
||||
|
||||
### Decision Tree
|
||||
|
||||
```
|
||||
New request?
|
||||
├─ Bug fix restoring spec behavior? → Fix directly
|
||||
├─ Typo/format/comment? → Fix directly
|
||||
├─ New feature/capability? → Create proposal
|
||||
├─ Breaking change? → Create proposal
|
||||
├─ Architecture change? → Create proposal
|
||||
└─ Unclear? → Create proposal (safer)
|
||||
```
|
||||
|
||||
### Proposal Structure
|
||||
|
||||
1. **Create directory:** `changes/[change-id]/` (kebab-case, verb-led, unique)
|
||||
|
||||
2. **Write proposal.md:**
|
||||
```markdown
|
||||
## Why
|
||||
[1-2 sentences on problem/opportunity]
|
||||
|
||||
## What Changes
|
||||
- [Bullet list of changes]
|
||||
- [Mark breaking changes with **BREAKING**]
|
||||
|
||||
## Impact
|
||||
- Affected specs: [list capabilities]
|
||||
- Affected code: [key files/systems]
|
||||
```
|
||||
|
||||
3. **Create spec deltas:** `specs/[capability]/spec.md`
|
||||
```markdown
|
||||
## ADDED Requirements
|
||||
### Requirement: New Feature
|
||||
The system SHALL provide...
|
||||
|
||||
#### Scenario: Success case
|
||||
- **WHEN** user performs action
|
||||
- **THEN** expected result
|
||||
|
||||
## MODIFIED Requirements
|
||||
### Requirement: Existing Feature
|
||||
[Complete modified requirement]
|
||||
|
||||
## REMOVED Requirements
|
||||
### Requirement: Old Feature
|
||||
**Reason**: [Why removing]
|
||||
**Migration**: [How to handle]
|
||||
```
|
||||
If multiple capabilities are affected, create multiple delta files under `changes/[change-id]/specs/<capability>/spec.md`—one per capability.
|
||||
|
||||
4. **Create tasks.md:**
|
||||
```markdown
|
||||
## 1. Implementation
|
||||
- [ ] 1.1 Create database schema
|
||||
- [ ] 1.2 Implement API endpoint
|
||||
- [ ] 1.3 Add frontend component
|
||||
- [ ] 1.4 Write tests
|
||||
```
|
||||
|
||||
5. **Create design.md when needed:**
|
||||
Create `design.md` if any of the following apply; otherwise omit it:
|
||||
- Cross-cutting change (multiple services/modules) or a new architectural pattern
|
||||
- New external dependency or significant data model changes
|
||||
- Security, performance, or migration complexity
|
||||
- Ambiguity that benefits from technical decisions before coding
|
||||
|
||||
Minimal `design.md` skeleton:
|
||||
```markdown
|
||||
## Context
|
||||
[Background, constraints, stakeholders]
|
||||
|
||||
## Goals / Non-Goals
|
||||
- Goals: [...]
|
||||
- Non-Goals: [...]
|
||||
|
||||
## Decisions
|
||||
- Decision: [What and why]
|
||||
- Alternatives considered: [Options + rationale]
|
||||
|
||||
## Risks / Trade-offs
|
||||
- [Risk] → Mitigation
|
||||
|
||||
## Migration Plan
|
||||
[Steps, rollback]
|
||||
|
||||
## Open Questions
|
||||
- [...]
|
||||
```
|
||||
|
||||
## Spec File Format
|
||||
|
||||
### Critical: Scenario Formatting
|
||||
|
||||
**CORRECT** (use #### headers):
|
||||
```markdown
|
||||
#### Scenario: User login success
|
||||
- **WHEN** valid credentials provided
|
||||
- **THEN** return JWT token
|
||||
```
|
||||
|
||||
**WRONG** (don't use bullets or bold):
|
||||
```markdown
|
||||
- **Scenario: User login** ❌
|
||||
**Scenario**: User login ❌
|
||||
### Scenario: User login ❌
|
||||
```
|
||||
|
||||
Every requirement MUST have at least one scenario.
|
||||
|
||||
### Requirement Wording
|
||||
- Use SHALL/MUST for normative requirements (avoid should/may unless intentionally non-normative)
|
||||
|
||||
### Delta Operations
|
||||
|
||||
- `## ADDED Requirements` - New capabilities
|
||||
- `## MODIFIED Requirements` - Changed behavior
|
||||
- `## REMOVED Requirements` - Deprecated features
|
||||
- `## RENAMED Requirements` - Name changes
|
||||
|
||||
Headers matched with `trim(header)` - whitespace ignored.
|
||||
|
||||
#### When to use ADDED vs MODIFIED
|
||||
- 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.
|
||||
- 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.
|
||||
- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.
|
||||
|
||||
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.
|
||||
|
||||
Authoring a MODIFIED requirement correctly:
|
||||
1) Locate the existing requirement in `openspec/specs/<capability>/spec.md`.
|
||||
2) Copy the entire requirement block (from `### Requirement: ...` through its scenarios).
|
||||
3) Paste it under `## MODIFIED Requirements` and edit to reflect the new behavior.
|
||||
4) Ensure the header text matches exactly (whitespace-insensitive) and keep at least one `#### Scenario:`.
|
||||
|
||||
Example for RENAMED:
|
||||
```markdown
|
||||
## RENAMED Requirements
|
||||
- FROM: `### Requirement: Login`
|
||||
- TO: `### Requirement: User Authentication`
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Errors
|
||||
|
||||
**"Change must have at least one delta"**
|
||||
- Check `changes/[name]/specs/` exists with .md files
|
||||
- Verify files have operation prefixes (## ADDED Requirements)
|
||||
|
||||
**"Requirement must have at least one scenario"**
|
||||
- Check scenarios use `#### Scenario:` format (4 hashtags)
|
||||
- Don't use bullet points or bold for scenario headers
|
||||
|
||||
**Silent scenario parsing failures**
|
||||
- Exact format required: `#### Scenario: Name`
|
||||
- Debug with: `openspec show [change] --json --deltas-only`
|
||||
|
||||
### Validation Tips
|
||||
|
||||
```bash
|
||||
# Always use strict mode for comprehensive checks
|
||||
openspec validate [change] --strict
|
||||
|
||||
# Debug delta parsing
|
||||
openspec show [change] --json | jq '.deltas'
|
||||
|
||||
# Check specific requirement
|
||||
openspec show [spec] --json -r 1
|
||||
```
|
||||
|
||||
## Happy Path Script
|
||||
|
||||
```bash
|
||||
# 1) Explore current state
|
||||
openspec spec list --long
|
||||
openspec list
|
||||
# Optional full-text search:
|
||||
# rg -n "Requirement:|Scenario:" openspec/specs
|
||||
# rg -n "^#|Requirement:" openspec/changes
|
||||
|
||||
# 2) Choose change id and scaffold
|
||||
CHANGE=add-two-factor-auth
|
||||
mkdir -p openspec/changes/$CHANGE/{specs/auth}
|
||||
printf "## Why\n...\n\n## What Changes\n- ...\n\n## Impact\n- ...\n" > openspec/changes/$CHANGE/proposal.md
|
||||
printf "## 1. Implementation\n- [ ] 1.1 ...\n" > openspec/changes/$CHANGE/tasks.md
|
||||
|
||||
# 3) Add deltas (example)
|
||||
cat > openspec/changes/$CHANGE/specs/auth/spec.md << 'EOF'
|
||||
## ADDED Requirements
|
||||
### Requirement: Two-Factor Authentication
|
||||
Users MUST provide a second factor during login.
|
||||
|
||||
#### Scenario: OTP required
|
||||
- **WHEN** valid credentials are provided
|
||||
- **THEN** an OTP challenge is required
|
||||
EOF
|
||||
|
||||
# 4) Validate
|
||||
openspec validate $CHANGE --strict
|
||||
```
|
||||
|
||||
## Multi-Capability Example
|
||||
|
||||
```
|
||||
openspec/changes/add-2fa-notify/
|
||||
├── proposal.md
|
||||
├── tasks.md
|
||||
└── specs/
|
||||
├── auth/
|
||||
│ └── spec.md # ADDED: Two-Factor Authentication
|
||||
└── notifications/
|
||||
└── spec.md # ADDED: OTP email notification
|
||||
```
|
||||
|
||||
auth/spec.md
|
||||
```markdown
|
||||
## ADDED Requirements
|
||||
### Requirement: Two-Factor Authentication
|
||||
...
|
||||
```
|
||||
|
||||
notifications/spec.md
|
||||
```markdown
|
||||
## ADDED Requirements
|
||||
### Requirement: OTP Email Notification
|
||||
...
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Simplicity First
|
||||
- Default to <100 lines of new code
|
||||
- Single-file implementations until proven insufficient
|
||||
- Avoid frameworks without clear justification
|
||||
- Choose boring, proven patterns
|
||||
|
||||
### Complexity Triggers
|
||||
Only add complexity with:
|
||||
- Performance data showing current solution too slow
|
||||
- Concrete scale requirements (>1000 users, >100MB data)
|
||||
- Multiple proven use cases requiring abstraction
|
||||
|
||||
### Clear References
|
||||
- Use `file.ts:42` format for code locations
|
||||
- Reference specs as `specs/auth/spec.md`
|
||||
- Link related changes and PRs
|
||||
|
||||
### Capability Naming
|
||||
- Use verb-noun: `user-auth`, `payment-capture`
|
||||
- Single purpose per capability
|
||||
- 10-minute understandability rule
|
||||
- Split if description needs "AND"
|
||||
|
||||
### Change ID Naming
|
||||
- Use kebab-case, short and descriptive: `add-two-factor-auth`
|
||||
- Prefer verb-led prefixes: `add-`, `update-`, `remove-`, `refactor-`
|
||||
- Ensure uniqueness; if taken, append `-2`, `-3`, etc.
|
||||
|
||||
## Tool Selection Guide
|
||||
|
||||
| Task | Tool | Why |
|
||||
|------|------|-----|
|
||||
| Find files by pattern | Glob | Fast pattern matching |
|
||||
| Search code content | Grep | Optimized regex search |
|
||||
| Read specific files | Read | Direct file access |
|
||||
| Explore unknown scope | Task | Multi-step investigation |
|
||||
|
||||
## Error Recovery
|
||||
|
||||
### Change Conflicts
|
||||
1. Run `openspec list` to see active changes
|
||||
2. Check for overlapping specs
|
||||
3. Coordinate with change owners
|
||||
4. Consider combining proposals
|
||||
|
||||
### Validation Failures
|
||||
1. Run with `--strict` flag
|
||||
2. Check JSON output for details
|
||||
3. Verify spec file format
|
||||
4. Ensure scenarios properly formatted
|
||||
|
||||
### Missing Context
|
||||
1. Read project.md first
|
||||
2. Check related specs
|
||||
3. Review recent archives
|
||||
4. Ask for clarification
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Stage Indicators
|
||||
- `changes/` - Proposed, not yet built
|
||||
- `specs/` - Built and deployed
|
||||
- `archive/` - Completed changes
|
||||
|
||||
### File Purposes
|
||||
- `proposal.md` - Why and what
|
||||
- `tasks.md` - Implementation steps
|
||||
- `design.md` - Technical decisions
|
||||
- `spec.md` - Requirements and behavior
|
||||
|
||||
### CLI Essentials
|
||||
```bash
|
||||
openspec list # What's in progress?
|
||||
openspec show [item] # View details
|
||||
openspec validate --strict # Is it correct?
|
||||
openspec archive <change-id> [--yes|-y] # Mark complete (add --yes for automation)
|
||||
```
|
||||
|
||||
Remember: Specs are truth. Changes are proposals. Keep them in sync.
|
||||
@@ -1,9 +0,0 @@
|
||||
## MODIFIED Requirements
|
||||
### Requirement: Slash Command Configuration
|
||||
The init command SHALL generate slash command files for supported editors using shared templates.
|
||||
|
||||
#### Scenario: Generating slash commands for Antigravity
|
||||
- **WHEN** the user selects Antigravity during initialization
|
||||
- **THEN** create `.agent/workflows/openspec-proposal.md`, `.agent/workflows/openspec-apply.md`, and `.agent/workflows/openspec-archive.md`
|
||||
- **AND** ensure each file begins with YAML frontmatter that contains only a `description: <stage summary>` field followed by the shared OpenSpec workflow instructions wrapped in managed markers
|
||||
- **AND** populate the workflow body with the same proposal/apply/archive guidance used for other tools so Antigravity behaves like Windsurf while pointing to the `.agent/workflows/` directory
|
||||
@@ -1,8 +0,0 @@
|
||||
## MODIFIED Requirements
|
||||
### Requirement: Slash Command Updates
|
||||
The update command SHALL refresh existing slash command files for configured tools without creating new ones, and ensure the OpenCode archive command accepts change ID arguments.
|
||||
|
||||
#### Scenario: Updating slash commands for Antigravity
|
||||
- **WHEN** `.agent/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh the OpenSpec-managed portion of each file so the workflow copy matches other tools while preserving the existing single-field `description` frontmatter
|
||||
- **AND** skip creating any missing workflow files during update, mirroring the behavior for Windsurf and other IDEs
|
||||
@@ -0,0 +1,20 @@
|
||||
## Why
|
||||
|
||||
Users and agents need a simple way to submit feedback about OpenSpec directly from the CLI. Currently there's no mechanism to collect user feedback, feature requests, or bug reports in a way that enables follow-up conversation. Using GitHub Issues allows us to track feedback, prevent spam via GitHub auth, and enables outreach to users.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add `openspec feedback <message>` CLI command
|
||||
- Leverage `gh` CLI for GitHub authentication and issue creation
|
||||
- Add `/feedback` skill for agent-assisted feedback with context enrichment
|
||||
- Ensure cross-platform compatibility (macOS, Linux, Windows)
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: New `cli-feedback` capability
|
||||
- Affected code:
|
||||
- `src/cli/index.ts` - Register feedback command
|
||||
- `src/commands/feedback.ts` - Command implementation using `gh` CLI
|
||||
- `src/core/templates/skill-templates.ts` - Feedback skill template
|
||||
- `src/core/completions/command-registry.ts` - Shell completions
|
||||
- External dependency: Requires `gh` CLI installed and authenticated
|
||||
@@ -0,0 +1,188 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Feedback command
|
||||
|
||||
The system SHALL provide an `openspec feedback` command that creates a GitHub Issue in the openspec repository using the `gh` CLI. The system SHALL use `execFileSync` with argument arrays to prevent shell injection vulnerabilities.
|
||||
|
||||
#### Scenario: Simple feedback submission
|
||||
|
||||
- **WHEN** user executes `openspec feedback "Great tool!"`
|
||||
- **THEN** the system executes `gh issue create` with title "Feedback: Great tool!"
|
||||
- **AND** the issue is created in the openspec repository
|
||||
- **AND** the issue has the `feedback` label
|
||||
- **AND** the system displays the created issue URL
|
||||
|
||||
#### Scenario: Safe command execution
|
||||
|
||||
- **WHEN** submitting feedback via `gh` CLI
|
||||
- **THEN** the system uses `execFileSync` with separate arguments array
|
||||
- **AND** user input is NOT passed through a shell
|
||||
- **AND** shell metacharacters (quotes, backticks, $(), etc.) are treated as literal text
|
||||
|
||||
#### Scenario: Feedback with body
|
||||
|
||||
- **WHEN** user executes `openspec feedback "Title here" --body "Detailed description..."`
|
||||
- **THEN** the system creates a GitHub Issue with the specified title
|
||||
- **AND** the issue body contains the detailed description
|
||||
- **AND** the issue body includes metadata (OpenSpec version, platform, timestamp)
|
||||
|
||||
### Requirement: GitHub CLI dependency
|
||||
|
||||
The system SHALL use `gh` CLI for automatic feedback submission when available, and provide a manual submission fallback when `gh` is not installed or not authenticated. The system SHALL use platform-appropriate commands to detect `gh` CLI availability.
|
||||
|
||||
#### Scenario: Missing gh CLI with fallback
|
||||
|
||||
- **WHEN** user runs `openspec feedback "message"`
|
||||
- **AND** `gh` CLI is not installed (not found in PATH)
|
||||
- **THEN** the system displays warning: "GitHub CLI not found. Manual submission required."
|
||||
- **AND** outputs structured feedback content with delimiters:
|
||||
- "--- FORMATTED FEEDBACK ---"
|
||||
- Title line
|
||||
- Labels line
|
||||
- Body content with metadata
|
||||
- "--- END FEEDBACK ---"
|
||||
- **AND** displays pre-filled GitHub issue URL for manual submission
|
||||
- **AND** exits with zero code (successful fallback)
|
||||
|
||||
#### Scenario: Cross-platform gh CLI detection on Unix
|
||||
|
||||
- **WHEN** system is running on macOS or Linux (platform is 'darwin' or 'linux')
|
||||
- **AND** checking if `gh` CLI is installed
|
||||
- **THEN** the system executes `which gh` command
|
||||
|
||||
#### Scenario: Cross-platform gh CLI detection on Windows
|
||||
|
||||
- **WHEN** system is running on Windows (platform is 'win32')
|
||||
- **AND** checking if `gh` CLI is installed
|
||||
- **THEN** the system executes `where gh` command
|
||||
|
||||
#### Scenario: Unauthenticated gh CLI with fallback
|
||||
|
||||
- **WHEN** user runs `openspec feedback "message"`
|
||||
- **AND** `gh` CLI is installed but not authenticated
|
||||
- **THEN** the system displays warning: "GitHub authentication required. Manual submission required."
|
||||
- **AND** outputs structured feedback content (same format as missing gh CLI scenario)
|
||||
- **AND** displays pre-filled GitHub issue URL for manual submission
|
||||
- **AND** displays authentication instructions: "To auto-submit in the future: gh auth login"
|
||||
- **AND** exits with zero code (successful fallback)
|
||||
|
||||
#### Scenario: Authenticated gh CLI
|
||||
|
||||
- **WHEN** user runs `openspec feedback "message"`
|
||||
- **AND** `gh auth status` returns success (authenticated)
|
||||
- **THEN** the system proceeds with feedback submission
|
||||
|
||||
### Requirement: Issue metadata
|
||||
|
||||
The system SHALL include relevant metadata in the GitHub Issue body.
|
||||
|
||||
#### Scenario: Standard metadata
|
||||
|
||||
- **WHEN** creating a GitHub Issue for feedback
|
||||
- **THEN** the issue body includes:
|
||||
- OpenSpec CLI version
|
||||
- Platform (darwin, linux, win32)
|
||||
- Submission timestamp
|
||||
- Separator line: "---\nSubmitted via OpenSpec CLI"
|
||||
|
||||
#### Scenario: Windows platform metadata
|
||||
|
||||
- **WHEN** creating a GitHub Issue for feedback on Windows
|
||||
- **THEN** the issue body includes "Platform: win32"
|
||||
- **AND** all platform detection uses Node.js `os.platform()` API
|
||||
|
||||
#### Scenario: No sensitive metadata
|
||||
|
||||
- **WHEN** creating a GitHub Issue for feedback
|
||||
- **THEN** the issue body does NOT include:
|
||||
- File paths from user's system
|
||||
- Project names or directory names
|
||||
- Environment variables
|
||||
- IP addresses
|
||||
|
||||
### Requirement: Feedback always works
|
||||
|
||||
The system SHALL allow feedback submission regardless of telemetry settings.
|
||||
|
||||
#### Scenario: Feedback with telemetry disabled
|
||||
|
||||
- **WHEN** user has disabled telemetry via `OPENSPEC_TELEMETRY=0`
|
||||
- **AND** user runs `openspec feedback "message"`
|
||||
- **THEN** the feedback is still submitted via `gh` CLI
|
||||
- **AND** telemetry events are not sent
|
||||
|
||||
#### Scenario: Feedback in CI environment
|
||||
|
||||
- **WHEN** `CI=true` is set in the environment
|
||||
- **AND** user runs `openspec feedback "message"`
|
||||
- **THEN** the feedback submission proceeds normally (if `gh` is available and authenticated)
|
||||
|
||||
### Requirement: Error handling
|
||||
|
||||
The system SHALL handle feedback submission errors gracefully.
|
||||
|
||||
#### Scenario: gh CLI execution failure
|
||||
|
||||
- **WHEN** `gh issue create` command fails
|
||||
- **THEN** the system displays the error output from `gh` CLI
|
||||
- **AND** exits with the same exit code as `gh`
|
||||
|
||||
#### Scenario: Network failure
|
||||
|
||||
- **WHEN** `gh` CLI reports network connectivity issues
|
||||
- **THEN** the system displays the error message from `gh`
|
||||
- **AND** suggests checking network connectivity
|
||||
- **AND** exits with non-zero code
|
||||
|
||||
### Requirement: Feedback skill for agents
|
||||
|
||||
The system SHALL provide a `/feedback` skill that guides agents through collecting and submitting user feedback.
|
||||
|
||||
#### Scenario: Agent-initiated feedback
|
||||
|
||||
- **WHEN** user invokes `/feedback` in an agent conversation
|
||||
- **THEN** the agent gathers context from the conversation
|
||||
- **AND** drafts a feedback issue with enriched content
|
||||
- **AND** anonymizes sensitive information
|
||||
- **AND** presents the draft to the user for approval
|
||||
- **AND** submits via `openspec feedback` command on user confirmation
|
||||
|
||||
#### Scenario: Context enrichment
|
||||
|
||||
- **WHEN** agent drafts feedback
|
||||
- **THEN** the agent includes relevant context such as:
|
||||
- What task was being performed
|
||||
- What worked well or poorly
|
||||
- Specific friction points or praise
|
||||
|
||||
#### Scenario: Anonymization
|
||||
|
||||
- **WHEN** agent drafts feedback
|
||||
- **THEN** the agent removes or replaces:
|
||||
- File paths with `<path>` or generic descriptions
|
||||
- API keys, tokens, secrets with `<redacted>`
|
||||
- Company/organization names with `<company>`
|
||||
- Personal names with `<user>`
|
||||
- Specific URLs with `<url>` unless public/relevant
|
||||
|
||||
#### Scenario: User confirmation required
|
||||
|
||||
- **WHEN** agent has drafted feedback
|
||||
- **THEN** the agent MUST show the complete draft to the user
|
||||
- **AND** ask for explicit approval before submitting
|
||||
- **AND** allow the user to request modifications
|
||||
- **AND** only submit after user confirms
|
||||
|
||||
### Requirement: Shell completions
|
||||
|
||||
The system SHALL provide shell completions for the feedback command.
|
||||
|
||||
#### Scenario: Command completion
|
||||
|
||||
- **WHEN** user types `openspec fee<TAB>`
|
||||
- **THEN** the shell completes to `openspec feedback`
|
||||
|
||||
#### Scenario: Flag completion
|
||||
|
||||
- **WHEN** user types `openspec feedback "msg" --<TAB>`
|
||||
- **THEN** the shell suggests available flags (`--body`)
|
||||
@@ -0,0 +1,30 @@
|
||||
## 1. Feedback Command
|
||||
|
||||
- [x] 1.1 Create `src/commands/feedback.ts` with command implementation
|
||||
- [x] 1.2 Check `gh` CLI availability using platform-appropriate command (`which` on Unix/macOS, `where` on Windows)
|
||||
- [x] 1.3 Check GitHub auth status with `gh auth status`
|
||||
- [x] 1.4 Execute `gh issue create` with formatted title and body using `execFileSync` to prevent shell injection
|
||||
- [x] 1.5 Display issue URL returned by `gh` CLI
|
||||
- [x] 1.6 Register `feedback <message>` command in `src/cli/index.ts`
|
||||
- [x] 1.7 Ensure cross-platform compatibility (macOS, Linux, Windows)
|
||||
|
||||
## 2. Shell Completions
|
||||
|
||||
- [x] 2.1 Add `feedback` command to command registry
|
||||
- [x] 2.2 Regenerate completion scripts for all shells
|
||||
|
||||
## 3. Feedback Skill
|
||||
|
||||
- [x] 3.1 Create feedback skill template in `skill-templates.ts`
|
||||
- [x] 3.2 Document context gathering workflow
|
||||
- [x] 3.3 Document anonymization rules
|
||||
- [x] 3.4 Document user confirmation flow
|
||||
|
||||
## 4. Testing
|
||||
|
||||
- [x] 4.1 Add unit tests for feedback command (mock `gh` subprocess calls)
|
||||
- [x] 4.2 Add integration test for full feedback flow with mocked `gh` CLI
|
||||
- [x] 4.3 Test error handling for missing `gh` CLI
|
||||
- [x] 4.4 Test error handling for unauthenticated `gh` session
|
||||
- [x] 4.5 Test cross-platform `gh` CLI detection (verify `which` on Unix, `where` on Windows)
|
||||
- [x] 4.6 Test platform metadata includes correct value for Windows (win32)
|
||||
@@ -1,11 +0,0 @@
|
||||
## Why
|
||||
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.
|
||||
|
||||
## What Changes
|
||||
- Add an `openspec scaffold <change-id>` CLI command that creates a change directory (if it does not already exist) with validated `proposal.md`, `tasks.md`, and spec delta templates.
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
## Impact
|
||||
- Affected specs: `specs/cli-scaffold`
|
||||
- Affected code: `src/cli/index.ts`, `src/commands`, `docs/`
|
||||
@@ -1,36 +0,0 @@
|
||||
## ADDED Requirements
|
||||
### Requirement: Scaffolding Command Registration
|
||||
The CLI SHALL expose an `openspec scaffold <change-id>` command that validates the change identifier before generating files.
|
||||
|
||||
#### Scenario: Registering scaffold command
|
||||
- **WHEN** a user runs `openspec scaffold add-user-notifications`
|
||||
- **THEN** the CLI SHALL reject invalid identifiers (non kebab-case) before proceeding
|
||||
- **AND** display usage documentation via `openspec scaffold --help`
|
||||
- **AND** exit with code 0 after successful scaffolding
|
||||
|
||||
### Requirement: Change Directory Structure
|
||||
The scaffold command SHALL create the standard change workspace (if it does not already exist) with proposal, tasks, optional design, and `specs/` directories laid out according to OpenSpec conventions.
|
||||
|
||||
#### Scenario: Generating change workspace
|
||||
- **WHEN** scaffolding a new change with id `add-user-notifications`
|
||||
- **THEN** create `openspec/changes/add-user-notifications/` if it does not exist
|
||||
- **AND** copy the default template bundle (proposal, tasks, design placeholders) into that directory in a single operation
|
||||
- **AND** create an empty `openspec/changes/add-user-notifications/specs/` directory ready for capability-specific deltas that will be authored later
|
||||
|
||||
### Requirement: Template Content Guidance
|
||||
The scaffold command SHALL populate generated Markdown files with OpenSpec-compliant templates so authors can copy, edit, and pass validation without reformatting.
|
||||
|
||||
#### Scenario: Populating proposal and tasks templates
|
||||
- **WHEN** the scaffold command writes `proposal.md`
|
||||
- **THEN** include the `## Why`, `## What Changes`, and `## Impact` headings with placeholder guidance text
|
||||
- **AND** ensure `tasks.md` starts with `## 1. Implementation` and numbered checklist items using `- [ ]` syntax
|
||||
- **AND** annotate optional sections (like `design.md`) with inline TODO comments so users understand when to keep or delete them
|
||||
- **AND** include a short reminder inside `specs/README.md` (or similar) instructing authors to add deltas once they know the affected capability
|
||||
|
||||
### Requirement: Idempotent Execution
|
||||
The scaffold command SHALL be safe to rerun, preserving user edits while filling in any missing managed sections.
|
||||
|
||||
#### Scenario: Rerunning scaffold on existing change
|
||||
- **WHEN** the command is executed again for an existing change directory containing user-edited files
|
||||
- **THEN** leave existing content untouched except for managed placeholder regions or missing files that need creation
|
||||
- **AND** update the filesystem summary to highlight which files were skipped, created, or refreshed
|
||||
@@ -1,12 +0,0 @@
|
||||
## 1. CLI scaffolding command
|
||||
- [ ] 1.1 Register an `openspec scaffold` command in the CLI entrypoint with `change-id` argument validation.
|
||||
- [ ] 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/<id>/`, creating the directory tree in a single pass.
|
||||
- [ ] 1.3 Detect when `openspec/changes/<id>/` already exists and exit with a clear error instead of overwriting user files.
|
||||
|
||||
## 2. Templates and documentation
|
||||
- [ ] 2.1 Update `openspec/AGENTS.md` quick reference so agents see `openspec scaffold` before drafting files manually.
|
||||
- [ ] 2.2 Refresh CLI docs/README/help text to mention the scaffold workflow, template bundle contents, and when to add spec deltas manually.
|
||||
|
||||
## 3. Test coverage
|
||||
- [ ] 3.1 Add unit tests covering name validation, template copying, and existing-directory failures.
|
||||
- [ ] 3.2 Add integration coverage ensuring a freshly scaffolded change (without deltas) passes `openspec validate --strict` until the author customizes it.
|
||||
@@ -0,0 +1,96 @@
|
||||
# Design: Add /opsx:verify Skill
|
||||
|
||||
## Architecture Decision: Dynamic Generation via Setup Command
|
||||
|
||||
### Context
|
||||
|
||||
All existing opsx experimental skills (explore, new, continue, apply, ff, sync, archive) are dynamically generated when users run `openspec artifact-experimental-setup`. They are not manually created files checked into the repository.
|
||||
|
||||
### Decision
|
||||
|
||||
**Integrate verify into the existing artifact-experimental-setup system rather than creating static skill files.**
|
||||
|
||||
### Rationale
|
||||
|
||||
1. **Consistency**: All 7 existing opsx skills follow this pattern. Adding verify as the 8th skill should follow the same architecture.
|
||||
|
||||
2. **Maintainability**: Template functions in `skill-templates.ts` are the single source of truth. Changes to skill definitions automatically propagate to all users when they re-run setup.
|
||||
|
||||
3. **Distribution**: Users get the verify skill automatically when running `openspec artifact-experimental-setup`, just like all other opsx skills. No special installation steps needed.
|
||||
|
||||
4. **Versioning**: Skills are generated from the installed npm package version, ensuring consistency between CLI version and skill behavior.
|
||||
|
||||
### Implementation Approach
|
||||
|
||||
#### 1. Template Functions
|
||||
|
||||
Add two template functions to `src/core/templates/skill-templates.ts`:
|
||||
|
||||
```typescript
|
||||
export function getVerifyChangeSkillTemplate(): SkillTemplate
|
||||
export function getOpsxVerifyCommandTemplate(): CommandTemplate
|
||||
```
|
||||
|
||||
These return the skill definition (for Agent Skills) and slash command definition (for explicit invocation).
|
||||
|
||||
#### 2. Setup Integration
|
||||
|
||||
Update `artifactExperimentalSetupCommand()` in `src/commands/artifact-workflow.ts`:
|
||||
|
||||
- Import both template functions
|
||||
- Add verify to the `skills` array (position 8)
|
||||
- Add verify to the `commands` array (position 8)
|
||||
- Update help text to list `/opsx:verify`
|
||||
|
||||
#### 3. Generated Artifacts
|
||||
|
||||
When users run `openspec artifact-experimental-setup`, the command creates:
|
||||
|
||||
- `.claude/skills/openspec-verify-change/SKILL.md` - Agent Skills format
|
||||
- `.claude/commands/opsx/verify.md` - Slash command format
|
||||
|
||||
Both are generated from the template functions, with YAML frontmatter automatically added.
|
||||
|
||||
### Alternatives Considered
|
||||
|
||||
**Alternative 1: Static skill files in repository**
|
||||
|
||||
Create `.claude/skills/openspec-verify-change/SKILL.md` as a static file in the OpenSpec repository.
|
||||
|
||||
**Rejected because:**
|
||||
- Inconsistent with all other opsx skills
|
||||
- Requires users to manually copy/update files
|
||||
- Versioning becomes complicated (repo version vs installed package version)
|
||||
- Breaks the established pattern
|
||||
|
||||
**Alternative 2: Separate verify setup command**
|
||||
|
||||
Add `openspec setup-verify` as a separate command.
|
||||
|
||||
**Rejected because:**
|
||||
- Fragments the setup experience
|
||||
- Users would need to run multiple commands
|
||||
- Doesn't scale if we add more skills in the future
|
||||
- Goes against the "setup once, get everything" philosophy
|
||||
|
||||
### Trade-offs
|
||||
|
||||
**Advantages:**
|
||||
- Consistent with existing architecture
|
||||
- Zero additional setup burden for users
|
||||
- Easy to update and maintain
|
||||
- Automatic version compatibility
|
||||
|
||||
**Disadvantages:**
|
||||
- Slightly more complex initial implementation (template functions + integration)
|
||||
- Requires understanding the setup system (but that's already documented)
|
||||
|
||||
### Verification
|
||||
|
||||
The implementation correctly follows this design if:
|
||||
|
||||
1. Both template functions exist in `skill-templates.ts`
|
||||
2. Verify appears in both skills and commands arrays in `artifact-workflow.ts`
|
||||
3. Help text mentions `/opsx:verify`
|
||||
4. Running `openspec artifact-experimental-setup` generates both skill and command files
|
||||
5. Build succeeds with no TypeScript errors
|
||||
@@ -0,0 +1,48 @@
|
||||
# Change: Add /opsx:verify Skill
|
||||
|
||||
## Why
|
||||
|
||||
Users need a way to validate that their implementation actually matches what was requested before archiving a change. Currently, there's no systematic way to check:
|
||||
- Whether all tasks are truly complete
|
||||
- Whether the implementation covers all spec requirements and scenarios
|
||||
- Whether the implementation follows the design decisions
|
||||
- Whether the code is coherent and makes sense
|
||||
|
||||
A user requested: "Can we get a :verify that will ensure that the implementation matches what was requested?"
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add `getVerifyChangeSkillTemplate()` function to `skill-templates.ts`
|
||||
- Add `getOpsxVerifyCommandTemplate()` function to `skill-templates.ts`
|
||||
- Integrate verify skill into `artifactExperimentalSetupCommand` in `artifact-workflow.ts`
|
||||
- Add verify to the skills and commands arrays in the setup command
|
||||
- Update help text to include `/opsx:verify` in the list of available commands
|
||||
- Create `opsx-verify-skill` capability spec
|
||||
|
||||
## Verification Dimensions
|
||||
|
||||
The skill verifies across three dimensions:
|
||||
|
||||
1. **Completeness** - Are all tasks done? Are all specs addressed?
|
||||
2. **Correctness** - Does the implementation match specs? Are scenarios covered?
|
||||
3. **Coherence** - Does the implementation make sense? Does it follow design.md?
|
||||
|
||||
## Output Format
|
||||
|
||||
Produces a prioritized report with:
|
||||
- Summary scorecard (tasks, specs, design adherence)
|
||||
- Critical issues first (must fix before archive)
|
||||
- Warnings second (should fix)
|
||||
- Suggestions third (nice to have)
|
||||
- Actionable fix recommendations for each issue
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: New `opsx-verify-skill` spec
|
||||
- Affected code:
|
||||
- `src/core/templates/skill-templates.ts` - Added 2 new template functions
|
||||
- `src/commands/artifact-workflow.ts` - Integrated verify into experimental setup
|
||||
- Generated artifacts: When users run `openspec artifact-experimental-setup`:
|
||||
- Creates `.claude/skills/openspec-verify-change/SKILL.md`
|
||||
- Creates `.claude/commands/opsx/verify.md`
|
||||
- Related skills: Works alongside `/opsx:apply` and before `/opsx:archive`
|
||||
@@ -0,0 +1,190 @@
|
||||
# opsx-verify-skill Specification
|
||||
|
||||
## Purpose
|
||||
Defines the agent skill for verifying that implementation matches change artifacts (specs, tasks, design).
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Verify Skill Invocation
|
||||
The system SHALL provide an `/opsx:verify` skill that validates implementation against change artifacts.
|
||||
|
||||
#### Scenario: Verify with change name provided
|
||||
- **WHEN** agent executes `/opsx:verify <change-name>`
|
||||
- **THEN** the agent verifies implementation for that specific change
|
||||
- **AND** produces a verification report
|
||||
|
||||
#### Scenario: Verify without change name
|
||||
- **WHEN** agent executes `/opsx:verify` without a change name
|
||||
- **THEN** the agent prompts user to select from available changes
|
||||
- **AND** shows only changes that have implementation tasks
|
||||
|
||||
#### Scenario: Change has no tasks
|
||||
- **WHEN** selected change has no tasks.md or tasks are empty
|
||||
- **THEN** the agent reports "No tasks to verify"
|
||||
- **AND** suggests running `/opsx:continue` to create tasks
|
||||
|
||||
### Requirement: Completeness Verification
|
||||
The agent SHALL verify that all required work has been completed.
|
||||
|
||||
#### Scenario: Task completion check
|
||||
- **WHEN** verifying completeness
|
||||
- **THEN** the agent reads tasks.md
|
||||
- **AND** counts tasks marked `- [x]` (complete) vs `- [ ]` (incomplete)
|
||||
- **AND** reports completion status with specific incomplete tasks listed
|
||||
|
||||
#### Scenario: Spec coverage check
|
||||
- **WHEN** verifying completeness
|
||||
- **AND** delta specs exist in `openspec/changes/<name>/specs/`
|
||||
- **THEN** the agent extracts all requirements from delta specs
|
||||
- **AND** searches codebase for implementation of each requirement
|
||||
- **AND** reports which requirements appear to have implementation vs which are missing
|
||||
|
||||
#### Scenario: All tasks complete
|
||||
- **WHEN** all tasks are marked complete
|
||||
- **THEN** report "Tasks: N/N complete"
|
||||
- **AND** mark completeness dimension as passed
|
||||
|
||||
#### Scenario: Incomplete tasks found
|
||||
- **WHEN** some tasks are incomplete
|
||||
- **THEN** report "Tasks: X/N complete"
|
||||
- **AND** list each incomplete task
|
||||
- **AND** mark as CRITICAL issue
|
||||
- **AND** suggest: "Complete remaining tasks or mark as done if already implemented"
|
||||
|
||||
### Requirement: Correctness Verification
|
||||
The agent SHALL verify that implementation matches the specifications.
|
||||
|
||||
#### Scenario: Requirement implementation mapping
|
||||
- **WHEN** verifying correctness
|
||||
- **THEN** for each requirement in delta specs:
|
||||
- Search codebase for implementation
|
||||
- Identify relevant files and line numbers
|
||||
- Assess whether implementation satisfies the requirement
|
||||
|
||||
#### Scenario: Scenario coverage check
|
||||
- **WHEN** verifying correctness
|
||||
- **THEN** for each scenario in delta specs:
|
||||
- Check if the scenario's conditions are handled in code
|
||||
- Check if tests exist that cover the scenario
|
||||
- Report coverage status
|
||||
|
||||
#### Scenario: Implementation matches spec
|
||||
- **WHEN** implementation appears to satisfy a requirement
|
||||
- **THEN** report which files/lines implement it
|
||||
- **AND** mark requirement as covered
|
||||
|
||||
#### Scenario: Implementation diverges from spec
|
||||
- **WHEN** implementation exists but doesn't match spec intent
|
||||
- **THEN** report the divergence as WARNING
|
||||
- **AND** explain what differs
|
||||
- **AND** suggest: either update implementation or update spec to match reality
|
||||
|
||||
#### Scenario: Missing implementation
|
||||
- **WHEN** no implementation found for a requirement
|
||||
- **THEN** report as CRITICAL issue
|
||||
- **AND** suggest: "Implement requirement X" with guidance on what's needed
|
||||
|
||||
### Requirement: Coherence Verification
|
||||
The agent SHALL verify that implementation is sensible and follows design decisions.
|
||||
|
||||
#### Scenario: Design.md adherence check
|
||||
- **WHEN** verifying coherence
|
||||
- **AND** design.md exists for the change
|
||||
- **THEN** extract key decisions from design.md
|
||||
- **AND** verify implementation follows those decisions
|
||||
- **AND** report any deviations
|
||||
|
||||
#### Scenario: No design.md
|
||||
- **WHEN** verifying coherence
|
||||
- **AND** no design.md exists
|
||||
- **THEN** skip design adherence check
|
||||
- **AND** note "No design.md to verify against"
|
||||
|
||||
#### Scenario: Design decision followed
|
||||
- **WHEN** implementation follows a design decision
|
||||
- **THEN** report as confirmed
|
||||
- **AND** cite evidence from code
|
||||
|
||||
#### Scenario: Design decision violated
|
||||
- **WHEN** implementation contradicts a design decision
|
||||
- **THEN** report as WARNING
|
||||
- **AND** explain the contradiction
|
||||
- **AND** suggest: either update implementation or update design.md
|
||||
|
||||
#### Scenario: Code pattern consistency
|
||||
- **WHEN** verifying coherence
|
||||
- **THEN** check if new code follows existing project patterns
|
||||
- **AND** flag any significant deviations as suggestions
|
||||
|
||||
### Requirement: Verification Report Format
|
||||
The agent SHALL produce a structured, prioritized report.
|
||||
|
||||
#### Scenario: Report summary
|
||||
- **WHEN** verification completes
|
||||
- **THEN** display summary scorecard:
|
||||
```
|
||||
## Verification Report: <change-name>
|
||||
|
||||
### Summary
|
||||
| Dimension | Status |
|
||||
|--------------|----------|
|
||||
| Completeness | X/Y |
|
||||
| Correctness | X/Y |
|
||||
| Coherence | Followed |
|
||||
```
|
||||
|
||||
#### Scenario: Issue prioritization
|
||||
- **WHEN** issues are found
|
||||
- **THEN** group and display in priority order:
|
||||
1. CRITICAL - Must fix before archive (missing implementation, incomplete tasks)
|
||||
2. WARNING - Should fix (divergence from spec/design, missing tests)
|
||||
3. SUGGESTION - Nice to fix (pattern inconsistencies, minor improvements)
|
||||
|
||||
#### Scenario: Actionable recommendations
|
||||
- **WHEN** reporting an issue
|
||||
- **THEN** include specific, actionable fix recommendation
|
||||
- **AND** reference relevant files and line numbers where applicable
|
||||
- **AND** avoid vague suggestions like "consider reviewing"
|
||||
|
||||
#### Scenario: All checks pass
|
||||
- **WHEN** no issues found across all dimensions
|
||||
- **THEN** display:
|
||||
```
|
||||
All checks passed. Ready for archive.
|
||||
```
|
||||
|
||||
#### Scenario: Critical issues found
|
||||
- **WHEN** CRITICAL issues exist
|
||||
- **THEN** display:
|
||||
```
|
||||
X critical issue(s) found. Fix before archiving.
|
||||
```
|
||||
- **AND** do NOT suggest running archive
|
||||
|
||||
#### Scenario: Only warnings/suggestions
|
||||
- **WHEN** no CRITICAL issues but warnings exist
|
||||
- **THEN** display:
|
||||
```
|
||||
No critical issues. Y warning(s) to consider.
|
||||
Ready for archive (with noted improvements).
|
||||
```
|
||||
|
||||
### Requirement: Flexible Artifact Handling
|
||||
The agent SHALL gracefully handle changes with varying artifact completeness.
|
||||
|
||||
#### Scenario: Minimal change (tasks only)
|
||||
- **WHEN** change has only tasks.md
|
||||
- **THEN** verify task completion only
|
||||
- **AND** skip spec and design checks
|
||||
- **AND** note which checks were skipped
|
||||
|
||||
#### Scenario: Change with specs but no design
|
||||
- **WHEN** change has tasks.md and delta specs but no design.md
|
||||
- **THEN** verify completeness and correctness
|
||||
- **AND** skip design adherence
|
||||
- **AND** still check code coherence against project patterns
|
||||
|
||||
#### Scenario: Full change (all artifacts)
|
||||
- **WHEN** change has proposal, design, specs, and tasks
|
||||
- **THEN** perform all verification checks
|
||||
- **AND** cross-reference artifacts for consistency
|
||||
@@ -0,0 +1,15 @@
|
||||
# Tasks: Add /opsx:verify Skill
|
||||
|
||||
## 1. Skill Template Functions
|
||||
- [x] 1.1 Add `getVerifyChangeSkillTemplate()` to skill-templates.ts
|
||||
- [x] 1.2 Add `getOpsxVerifyCommandTemplate()` to skill-templates.ts
|
||||
|
||||
## 2. Integration with artifact-experimental-setup
|
||||
- [x] 2.1 Import verify template functions in artifact-workflow.ts
|
||||
- [x] 2.2 Add verify to skills array in artifactExperimentalSetupCommand
|
||||
- [x] 2.3 Add verify to commands array in artifactExperimentalSetupCommand
|
||||
- [x] 2.4 Add verify to help text output
|
||||
|
||||
## 3. Verification (Build & Test)
|
||||
- [x] 3.1 Verify TypeScript compilation succeeds
|
||||
- [x] 3.2 Verify all 8 skills are now included (was 7, now 8)
|
||||
@@ -0,0 +1,15 @@
|
||||
# Change Proposal: Extend Shell Completions
|
||||
|
||||
## Why
|
||||
|
||||
Zsh completions provide an excellent developer experience, but many developers use bash, fish, or PowerShell. Extending completion support to these shells removes friction for the majority of developers who don't use Zsh.
|
||||
|
||||
## What Changes
|
||||
|
||||
This change adds bash, fish, and PowerShell completion support following the same architectural patterns, documentation methodology, and testing rigor established for Zsh completions.
|
||||
|
||||
## Deltas
|
||||
|
||||
- **Spec:** `cli-completion`
|
||||
- **Operation:** MODIFIED
|
||||
- **Description:** Extend completion generation, installation, and testing requirements to support bash, fish, and PowerShell while maintaining the existing Zsh implementation and architectural patterns
|
||||
+328
@@ -0,0 +1,328 @@
|
||||
# cli-completion Spec Delta
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Native Shell Behavior Integration
|
||||
|
||||
The completion system SHALL respect and integrate with each supported shell's native completion patterns and user interaction model.
|
||||
|
||||
#### Scenario: Zsh native completion
|
||||
|
||||
- **WHEN** generating Zsh completion scripts
|
||||
- **THEN** use Zsh completion system with `_arguments`, `_describe`, and `compadd`
|
||||
- **AND** completions SHALL trigger on single TAB (standard Zsh behavior)
|
||||
- **AND** display as an interactive menu that users navigate with TAB/arrow keys
|
||||
- **AND** support Oh My Zsh's enhanced menu styling automatically
|
||||
|
||||
#### Scenario: Bash native completion
|
||||
|
||||
- **WHEN** generating Bash completion scripts
|
||||
- **THEN** use Bash completion with `complete` builtin and `COMPREPLY` array
|
||||
- **AND** completions SHALL trigger on double TAB (standard Bash behavior)
|
||||
- **AND** display as space-separated list or column format
|
||||
- **AND** support both bash-completion v1 and v2 patterns
|
||||
|
||||
#### Scenario: Fish native completion
|
||||
|
||||
- **WHEN** generating Fish completion scripts
|
||||
- **THEN** use Fish's `complete` command with conditions
|
||||
- **AND** completions SHALL trigger on single TAB with auto-suggestion preview
|
||||
- **AND** display with Fish's native coloring and description alignment
|
||||
- **AND** leverage Fish's built-in caching automatically
|
||||
|
||||
#### Scenario: PowerShell native completion
|
||||
|
||||
- **WHEN** generating PowerShell completion scripts
|
||||
- **THEN** use `Register-ArgumentCompleter` with scriptblock
|
||||
- **AND** completions SHALL trigger on TAB with cycling behavior
|
||||
- **AND** display with PowerShell's native completion UI
|
||||
- **AND** support both Windows PowerShell 5.1 and PowerShell Core 7+
|
||||
|
||||
#### Scenario: No custom UX patterns
|
||||
|
||||
- **WHEN** implementing completion for any shell
|
||||
- **THEN** do NOT attempt to customize completion trigger behavior
|
||||
- **AND** do NOT override shell-specific navigation patterns
|
||||
- **AND** ensure completions feel native to experienced users of that shell
|
||||
|
||||
### Requirement: Shell Detection
|
||||
|
||||
The completion system SHALL automatically detect the user's current shell environment.
|
||||
|
||||
#### Scenario: Detecting Zsh from environment
|
||||
|
||||
- **WHEN** no shell is explicitly specified
|
||||
- **THEN** read the `$SHELL` environment variable
|
||||
- **AND** extract the shell name from the path (e.g., `/bin/zsh` → `zsh`)
|
||||
- **AND** validate the shell is one of: `zsh`, `bash`, `fish`, `powershell`
|
||||
- **AND** throw an error if the shell is not supported
|
||||
|
||||
#### Scenario: Detecting Bash from environment
|
||||
|
||||
- **WHEN** `$SHELL` contains `bash` in the path
|
||||
- **THEN** detect shell as `bash`
|
||||
- **AND** proceed with bash-specific completion logic
|
||||
|
||||
#### Scenario: Detecting Fish from environment
|
||||
|
||||
- **WHEN** `$SHELL` contains `fish` in the path
|
||||
- **THEN** detect shell as `fish`
|
||||
- **AND** proceed with fish-specific completion logic
|
||||
|
||||
#### Scenario: Detecting PowerShell from environment
|
||||
|
||||
- **WHEN** `$PSModulePath` environment variable is present
|
||||
- **THEN** detect shell as `powershell`
|
||||
- **AND** proceed with PowerShell-specific completion logic
|
||||
|
||||
#### Scenario: Unsupported shell detection
|
||||
|
||||
- **WHEN** shell path indicates an unsupported shell
|
||||
- **THEN** throw error: "Shell '<name>' is not supported. Supported shells: zsh, bash, fish, powershell"
|
||||
|
||||
### Requirement: Completion Generation
|
||||
|
||||
The completion command SHALL generate completion scripts for all supported shells on demand.
|
||||
|
||||
#### Scenario: Generating Zsh completion
|
||||
|
||||
- **WHEN** user executes `openspec completion generate zsh`
|
||||
- **THEN** output a complete Zsh completion script to stdout
|
||||
- **AND** include completions for all commands: init, list, show, validate, archive, view, update, change, spec, completion
|
||||
- **AND** include all command-specific flags and options
|
||||
- **AND** use Zsh's `_arguments` and `_describe` built-in functions
|
||||
- **AND** support dynamic completion for change and spec IDs
|
||||
|
||||
#### Scenario: Generating Bash completion
|
||||
|
||||
- **WHEN** user executes `openspec completion generate bash`
|
||||
- **THEN** output a complete Bash completion script to stdout
|
||||
- **AND** include completions for all commands and subcommands
|
||||
- **AND** use `complete -F` with custom completion function
|
||||
- **AND** populate `COMPREPLY` with appropriate suggestions
|
||||
- **AND** support dynamic completion for change and spec IDs via `openspec __complete`
|
||||
|
||||
#### Scenario: Generating Fish completion
|
||||
|
||||
- **WHEN** user executes `openspec completion generate fish`
|
||||
- **THEN** output a complete Fish completion script to stdout
|
||||
- **AND** use `complete -c openspec` with conditions
|
||||
- **AND** include command-specific completions with `--condition` predicates
|
||||
- **AND** support dynamic completion for change and spec IDs via `openspec __complete`
|
||||
- **AND** include descriptions for each completion option
|
||||
|
||||
#### Scenario: Generating PowerShell completion
|
||||
|
||||
- **WHEN** user executes `openspec completion generate powershell`
|
||||
- **THEN** output a complete PowerShell completion script to stdout
|
||||
- **AND** use `Register-ArgumentCompleter -CommandName openspec`
|
||||
- **AND** implement scriptblock that handles command context
|
||||
- **AND** support dynamic completion for change and spec IDs via `openspec __complete`
|
||||
- **AND** return `[System.Management.Automation.CompletionResult]` objects
|
||||
|
||||
### Requirement: Installation Automation
|
||||
|
||||
The completion command SHALL automatically install completion scripts into shell configuration files for all supported shells.
|
||||
|
||||
#### Scenario: Installing for Oh My Zsh
|
||||
|
||||
- **WHEN** user executes `openspec completion install zsh`
|
||||
- **THEN** detect if Oh My Zsh is installed by checking for `$ZSH` environment variable or `~/.oh-my-zsh/` directory
|
||||
- **AND** create custom completions directory at `~/.oh-my-zsh/custom/completions/` if it doesn't exist
|
||||
- **AND** write completion script to `~/.oh-my-zsh/custom/completions/_openspec`
|
||||
- **AND** ensure `~/.oh-my-zsh/custom/completions` is in `$fpath` by updating `~/.zshrc` if needed
|
||||
- **AND** display success message with instruction to run `exec zsh` or restart terminal
|
||||
|
||||
#### Scenario: Installing for standard Zsh
|
||||
|
||||
- **WHEN** user executes `openspec completion install zsh` and Oh My Zsh is not detected
|
||||
- **THEN** create completions directory at `~/.zsh/completions/` if it doesn't exist
|
||||
- **AND** write completion script to `~/.zsh/completions/_openspec`
|
||||
- **AND** add `fpath=(~/.zsh/completions $fpath)` to `~/.zshrc` if not already present
|
||||
- **AND** add `autoload -Uz compinit && compinit` to `~/.zshrc` if not already present
|
||||
- **AND** display success message with instruction to run `exec zsh` or restart terminal
|
||||
|
||||
#### Scenario: Installing for Bash with bash-completion
|
||||
|
||||
- **WHEN** user executes `openspec completion install bash`
|
||||
- **THEN** detect if bash-completion is installed by checking for `/usr/share/bash-completion` or `/etc/bash_completion.d`
|
||||
- **AND** if bash-completion is available, write to `/etc/bash_completion.d/openspec` (with sudo) or `~/.local/share/bash-completion/completions/openspec`
|
||||
- **AND** if bash-completion is not available, write to `~/.bash_completion.d/openspec` and source it from `~/.bashrc`
|
||||
- **AND** add sourcing line to `~/.bashrc` using marker-based updates if needed
|
||||
- **AND** display success message with instruction to run `exec bash` or restart terminal
|
||||
|
||||
#### Scenario: Installing for Fish
|
||||
|
||||
- **WHEN** user executes `openspec completion install fish`
|
||||
- **THEN** create Fish completions directory at `~/.config/fish/completions/` if it doesn't exist
|
||||
- **AND** write completion script to `~/.config/fish/completions/openspec.fish`
|
||||
- **AND** Fish automatically loads completions from this directory (no config file modification needed)
|
||||
- **AND** display success message indicating completions are immediately available
|
||||
|
||||
#### Scenario: Installing for PowerShell
|
||||
|
||||
- **WHEN** user executes `openspec completion install powershell`
|
||||
- **THEN** detect PowerShell profile location via `$PROFILE` environment variable or default paths
|
||||
- **AND** create profile directory if it doesn't exist
|
||||
- **AND** add completion script import to profile using marker-based updates
|
||||
- **AND** write completion script to PowerShell modules directory or alongside profile
|
||||
- **AND** display success message with instruction to restart PowerShell or run `. $PROFILE`
|
||||
|
||||
#### Scenario: Auto-detecting shell for installation
|
||||
|
||||
- **WHEN** user executes `openspec completion install` without specifying a shell
|
||||
- **THEN** detect current shell using shell detection logic
|
||||
- **AND** install completion for the detected shell (zsh, bash, fish, or powershell)
|
||||
- **AND** display which shell was detected
|
||||
|
||||
#### Scenario: Already installed
|
||||
|
||||
- **WHEN** completion is already installed for the target shell
|
||||
- **THEN** display message indicating completion is already installed
|
||||
- **AND** offer to reinstall/update by overwriting existing files
|
||||
- **AND** exit with code 0
|
||||
|
||||
### Requirement: Uninstallation
|
||||
|
||||
The completion command SHALL remove installed completion scripts and configuration for all supported shells.
|
||||
|
||||
#### Scenario: Uninstalling Zsh completion
|
||||
|
||||
- **WHEN** user executes `openspec completion uninstall zsh`
|
||||
- **THEN** prompt for confirmation before proceeding (unless `--yes` flag provided)
|
||||
- **AND** if user declines, cancel uninstall and display "Uninstall cancelled."
|
||||
- **AND** if user confirms, remove `~/.oh-my-zsh/custom/completions/_openspec` if Oh My Zsh is detected
|
||||
- **AND** remove `~/.zsh/completions/_openspec` if standard Zsh setup is detected
|
||||
- **AND** remove fpath modifications from `~/.zshrc` using marker-based removal
|
||||
- **AND** display success message
|
||||
|
||||
#### Scenario: Uninstalling Bash completion
|
||||
|
||||
- **WHEN** user executes `openspec completion uninstall bash`
|
||||
- **THEN** prompt for confirmation (unless `--yes` flag provided)
|
||||
- **AND** if user confirms, remove completion file from bash-completion directory or `~/.bash_completion.d/`
|
||||
- **AND** remove sourcing lines from `~/.bashrc` using marker-based removal
|
||||
- **AND** display success message
|
||||
|
||||
#### Scenario: Uninstalling Fish completion
|
||||
|
||||
- **WHEN** user executes `openspec completion uninstall fish`
|
||||
- **THEN** prompt for confirmation (unless `--yes` flag provided)
|
||||
- **AND** if user confirms, remove `~/.config/fish/completions/openspec.fish`
|
||||
- **AND** display success message (no config file modification needed)
|
||||
|
||||
#### Scenario: Uninstalling PowerShell completion
|
||||
|
||||
- **WHEN** user executes `openspec completion uninstall powershell`
|
||||
- **THEN** prompt for confirmation (unless `--yes` flag provided)
|
||||
- **AND** if user confirms, remove completion import from PowerShell profile using marker-based removal
|
||||
- **AND** remove completion script file
|
||||
- **AND** display success message
|
||||
|
||||
#### Scenario: Auto-detecting shell for uninstallation
|
||||
|
||||
- **WHEN** user executes `openspec completion uninstall` without specifying a shell
|
||||
- **THEN** detect current shell and uninstall completion for that shell
|
||||
|
||||
#### Scenario: Not installed
|
||||
|
||||
- **WHEN** attempting to uninstall completion that isn't installed
|
||||
- **THEN** display error message indicating completion is not installed
|
||||
- **AND** exit with code 1
|
||||
|
||||
### Requirement: Architecture Patterns
|
||||
|
||||
The completion implementation SHALL follow clean architecture principles with TypeScript best practices, supporting multiple shells through a plugin-based pattern.
|
||||
|
||||
#### Scenario: Shell-specific generators
|
||||
|
||||
- **WHEN** implementing completion generators
|
||||
- **THEN** create generator classes for each shell: `ZshGenerator`, `BashGenerator`, `FishGenerator`, `PowerShellGenerator`
|
||||
- **AND** implement a common `CompletionGenerator` interface with method:
|
||||
- `generate(commands: CommandDefinition[]): string` - Returns complete shell script
|
||||
- **AND** each generator handles shell-specific syntax, escaping, and patterns
|
||||
- **AND** all generators consume the same `CommandDefinition[]` from the command registry
|
||||
|
||||
#### Scenario: Shell-specific installers
|
||||
|
||||
- **WHEN** implementing completion installers
|
||||
- **THEN** create installer classes for each shell: `ZshInstaller`, `BashInstaller`, `FishInstaller`, `PowerShellInstaller`
|
||||
- **AND** implement a common `CompletionInstaller` interface with methods:
|
||||
- `install(script: string): Promise<InstallationResult>` - Installs completion script
|
||||
- `uninstall(): Promise<{ success: boolean; message: string }>` - Removes completion
|
||||
- **AND** each installer handles shell-specific paths, config files, and installation patterns
|
||||
|
||||
#### Scenario: Factory pattern for shell selection
|
||||
|
||||
- **WHEN** selecting shell-specific implementation
|
||||
- **THEN** use `CompletionFactory` class with static methods:
|
||||
- `createGenerator(shell: SupportedShell): CompletionGenerator`
|
||||
- `createInstaller(shell: SupportedShell): CompletionInstaller`
|
||||
- **AND** factory uses switch statements with TypeScript exhaustiveness checking
|
||||
- **AND** adding new shell requires updating `SupportedShell` type and factory cases
|
||||
|
||||
#### Scenario: Dynamic completion providers
|
||||
|
||||
- **WHEN** implementing dynamic completions
|
||||
- **THEN** create a `CompletionProvider` class that encapsulates project discovery logic
|
||||
- **AND** implement methods:
|
||||
- `getChangeIds(): Promise<string[]>` - Discovers active change IDs
|
||||
- `getSpecIds(): Promise<string[]>` - Discovers spec IDs
|
||||
- `isOpenSpecProject(): boolean` - Checks if current directory is OpenSpec-enabled
|
||||
- **AND** implement caching with 2-second TTL using class properties
|
||||
|
||||
#### Scenario: Command registry
|
||||
|
||||
- **WHEN** defining completable commands
|
||||
- **THEN** create a centralized `CommandDefinition` type with properties:
|
||||
- `name: string` - Command name
|
||||
- `description: string` - Help text
|
||||
- `flags: FlagDefinition[]` - Available flags
|
||||
- `acceptsPositional: boolean` - Whether command takes positional arguments
|
||||
- `positionalType: string` - Type of positional (change-id, spec-id, path, shell)
|
||||
- `subcommands?: CommandDefinition[]` - Nested subcommands
|
||||
- **AND** export a `COMMAND_REGISTRY` constant with all command definitions
|
||||
- **AND** all generators consume this registry to ensure consistency across shells
|
||||
|
||||
#### Scenario: Type-safe shell detection
|
||||
|
||||
- **WHEN** implementing shell detection
|
||||
- **THEN** define a `SupportedShell` type as literal type: `'zsh' | 'bash' | 'fish' | 'powershell'`
|
||||
- **AND** implement `detectShell()` function in `src/utils/shell-detection.ts`
|
||||
- **AND** return detected shell or throw error with supported shells list
|
||||
|
||||
### Requirement: Testing Support
|
||||
|
||||
The completion implementation SHALL be testable with unit and integration tests for all supported shells.
|
||||
|
||||
#### Scenario: Mock shell environment
|
||||
|
||||
- **WHEN** writing tests for shell detection
|
||||
- **THEN** allow overriding `$SHELL` and `$PSModulePath` environment variables
|
||||
- **AND** use dependency injection for file system operations
|
||||
- **AND** test detection for all four shells independently
|
||||
|
||||
#### Scenario: Generator output verification
|
||||
|
||||
- **WHEN** testing completion generators
|
||||
- **THEN** create test suite for each shell generator (zsh, bash, fish, powershell)
|
||||
- **AND** verify generated scripts contain expected patterns for that shell
|
||||
- **AND** test that command registry is properly consumed
|
||||
- **AND** ensure dynamic completion placeholders are present
|
||||
- **AND** verify shell-specific syntax and escaping
|
||||
|
||||
#### Scenario: Installer simulation
|
||||
|
||||
- **WHEN** testing installation logic
|
||||
- **THEN** create test suite for each shell installer
|
||||
- **AND** use temporary test directories instead of actual home directories
|
||||
- **AND** verify file creation without modifying real shell configurations
|
||||
- **AND** test path resolution logic independently
|
||||
- **AND** mock file system operations to avoid side effects
|
||||
|
||||
#### Scenario: Cross-shell consistency
|
||||
|
||||
- **WHEN** testing completion behavior
|
||||
- **THEN** verify all shells support the same commands and flags
|
||||
- **AND** verify dynamic completions work consistently across shells
|
||||
- **AND** ensure error messages are consistent across shells
|
||||
@@ -0,0 +1,49 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## Phase 1: Foundation and Bash Support
|
||||
|
||||
- [x] Update `SupportedShell` type in `src/utils/shell-detection.ts` to include `'bash' | 'fish' | 'powershell'`
|
||||
- [x] Extend shell detection logic to recognize bash, fish, and PowerShell from environment variables
|
||||
- [x] Create `src/core/completions/generators/bash-generator.ts` implementing `CompletionGenerator` interface
|
||||
- [x] Create `src/core/completions/installers/bash-installer.ts` implementing `CompletionInstaller` interface
|
||||
- [x] Update `CompletionFactory.createGenerator()` to support bash
|
||||
- [x] Update `CompletionFactory.createInstaller()` to support bash
|
||||
- [x] Create test file `test/core/completions/generators/bash-generator.test.ts` mirroring zsh test structure
|
||||
- [x] Create test file `test/core/completions/installers/bash-installer.test.ts` mirroring zsh test structure
|
||||
- [x] Verify bash completions work manually: `openspec completion install bash && exec bash`
|
||||
|
||||
## Phase 2: Fish Support
|
||||
|
||||
- [x] Create `src/core/completions/generators/fish-generator.ts` implementing `CompletionGenerator` interface
|
||||
- [x] Create `src/core/completions/installers/fish-installer.ts` implementing `CompletionInstaller` interface
|
||||
- [x] Update `CompletionFactory.createGenerator()` to support fish
|
||||
- [x] Update `CompletionFactory.createInstaller()` to support fish
|
||||
- [x] Create test file `test/core/completions/generators/fish-generator.test.ts`
|
||||
- [x] Create test file `test/core/completions/installers/fish-installer.test.ts`
|
||||
- [x] Verify fish completions work manually: `openspec completion install fish`
|
||||
|
||||
## Phase 3: PowerShell Support
|
||||
|
||||
- [x] Create `src/core/completions/generators/powershell-generator.ts` implementing `CompletionGenerator` interface
|
||||
- [x] Create `src/core/completions/installers/powershell-installer.ts` implementing `CompletionInstaller` interface
|
||||
- [x] Update `CompletionFactory.createGenerator()` to support powershell
|
||||
- [x] Update `CompletionFactory.createInstaller()` to support powershell
|
||||
- [x] Create test file `test/core/completions/generators/powershell-generator.test.ts`
|
||||
- [x] Create test file `test/core/completions/installers/powershell-installer.test.ts`
|
||||
- [x] Verify PowerShell completions work manually on Windows or macOS PowerShell
|
||||
|
||||
## Phase 4: Documentation and Testing
|
||||
|
||||
- [x] Update `CLAUDE.md` or relevant documentation to mention all four supported shells
|
||||
- [x] Add cross-shell consistency test verifying all shells support same commands
|
||||
- [x] Run `pnpm test` to ensure all tests pass
|
||||
- [x] Run `pnpm run build` to verify TypeScript compilation
|
||||
- [x] Test all shells on different platforms (Linux for bash/fish/zsh, Windows/macOS for PowerShell)
|
||||
|
||||
## Phase 5: Validation and Cleanup
|
||||
|
||||
- [x] Run `openspec validate extend-shell-completions --strict` and resolve all issues
|
||||
- [x] Update error messages to list all four supported shells
|
||||
- [x] Verify `openspec completion --help` documentation is current
|
||||
- [x] Test auto-detection works for all shells
|
||||
- [x] Ensure uninstall works cleanly for all shells
|
||||
@@ -0,0 +1,112 @@
|
||||
## Context
|
||||
|
||||
Slice 4 of the artifact workflow POC. The core functionality (ArtifactGraph, InstructionLoader, change-utils) is complete. This slice adds CLI commands to expose the artifact workflow to users.
|
||||
|
||||
**Key constraint**: This is experimental. Commands must be isolated for easy removal if the feature doesn't work out.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
- **Goals:**
|
||||
- Expose artifact workflow status and instructions via CLI
|
||||
- Provide fluid UX with top-level verb commands
|
||||
- Support both human-readable and JSON output
|
||||
- Enable agents to programmatically query workflow state
|
||||
- Keep implementation isolated for easy removal
|
||||
|
||||
- **Non-Goals:**
|
||||
- Interactive artifact creation wizards (future work)
|
||||
- Schema management commands (deferred)
|
||||
- Auto-detection of active change (CLI is deterministic, agents infer)
|
||||
|
||||
## Decisions
|
||||
|
||||
### Command Structure: Top-Level Verbs
|
||||
|
||||
Commands are top-level for maximum fluidity:
|
||||
|
||||
```
|
||||
openspec status --change <id>
|
||||
openspec next --change <id>
|
||||
openspec instructions <artifact> --change <id>
|
||||
openspec templates [--schema <name>]
|
||||
openspec new change <name>
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- Most fluid UX - fewest keystrokes
|
||||
- Commands are unique enough to avoid conflicts
|
||||
- Simple mental model for users
|
||||
|
||||
**Trade-off accepted:** Slight namespace pollution, but commands are distinct and can be removed cleanly.
|
||||
|
||||
### Experimental Isolation
|
||||
|
||||
All artifact workflow commands are implemented in a single file:
|
||||
|
||||
```
|
||||
src/commands/artifact-workflow.ts
|
||||
```
|
||||
|
||||
**To remove the feature:**
|
||||
1. Delete `src/commands/artifact-workflow.ts`
|
||||
2. Remove ~5 lines from `src/cli/index.ts`
|
||||
|
||||
No other files touched, no risk to stable functionality.
|
||||
|
||||
### Deterministic CLI with Explicit `--change`
|
||||
|
||||
All change-specific commands require `--change <id>`:
|
||||
|
||||
```bash
|
||||
openspec status --change add-auth # explicit, works
|
||||
openspec status # error: missing --change
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- CLI is pure, testable, no hidden state
|
||||
- Agents infer change from conversation and pass explicitly
|
||||
- No config file tracking "active change"
|
||||
- Consistent with POC design philosophy
|
||||
|
||||
### New Change Command Structure
|
||||
|
||||
Creating changes uses explicit subcommand:
|
||||
|
||||
```bash
|
||||
openspec new change add-feature
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- `openspec new <name>` is ambiguous (new what?)
|
||||
- `openspec new change <name>` is clear and extensible
|
||||
- Can add `openspec new spec <name>` later if needed
|
||||
|
||||
### Output Formats
|
||||
|
||||
- **Default**: Human-readable text with visual indicators
|
||||
- Status: `[x]` done, `[ ]` ready, `[-]` blocked
|
||||
- Colors: green (done), yellow (ready), red (blocked)
|
||||
- **JSON** (`--json`): Machine-readable for scripts and agents
|
||||
|
||||
### Error Handling
|
||||
|
||||
- Missing `--change`: Error listing available changes
|
||||
- Unknown change: Error with suggestion
|
||||
- Unknown artifact: Error listing valid artifacts
|
||||
- Missing schema: Error with schema resolution details
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| Top-level commands pollute namespace | Commands are distinct; isolated for easy removal |
|
||||
| `status` confused with git | Context (`--change`) makes it clear |
|
||||
| Feature doesn't work out | Single file deletion removes everything |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- All commands in `src/commands/artifact-workflow.ts`
|
||||
- Imports from `src/core/artifact-graph/` for all operations
|
||||
- Uses `getActiveChangeIds()` from `item-discovery.ts` for change listing
|
||||
- Follows existing CLI patterns (ora spinners, commander.js options)
|
||||
- Help text marks commands as "Experimental"
|
||||
@@ -0,0 +1,33 @@
|
||||
## Why
|
||||
|
||||
The ArtifactGraph (Slice 1) and InstructionLoader (Slice 3) provide programmatic APIs for artifact-based workflow management. Users currently have no CLI interface to:
|
||||
- See artifact completion status for a change
|
||||
- Discover what artifacts are ready to create
|
||||
- Get enriched instructions for creating artifacts
|
||||
- Create new changes with proper validation
|
||||
|
||||
This proposal adds CLI commands that expose the artifact workflow functionality to users and agents.
|
||||
|
||||
## What Changes
|
||||
|
||||
- **NEW**: `openspec status --change <id>` shows artifact completion state
|
||||
- **NEW**: `openspec next --change <id>` shows artifacts ready to create
|
||||
- **NEW**: `openspec instructions <artifact> --change <id>` outputs enriched template
|
||||
- **NEW**: `openspec templates [--schema <name>]` shows resolved template paths
|
||||
- **NEW**: `openspec new change <name>` creates a new change directory
|
||||
|
||||
All commands are top-level for fluid UX. They integrate with existing core modules:
|
||||
- Uses `loadChangeContext()`, `formatChangeStatus()`, `generateInstructions()` from instruction-loader
|
||||
- Uses `ArtifactGraph`, `detectCompleted()` from artifact-graph
|
||||
- Uses `createChange()`, `validateChangeName()` from change-utils
|
||||
|
||||
**Experimental isolation**: All commands are implemented in a single file (`src/commands/artifact-workflow.ts`) for easy removal if the feature doesn't work out. Help text marks them as experimental.
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: NEW `cli-artifact-workflow` capability
|
||||
- Affected code:
|
||||
- `src/cli/index.ts` - register new commands
|
||||
- `src/commands/artifact-workflow.ts` - new command implementations
|
||||
- No changes to existing commands or specs
|
||||
- Builds on completed Slice 1, 2, and 3 implementations
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
# cli-artifact-workflow Specification
|
||||
|
||||
## Purpose
|
||||
CLI commands for artifact workflow operations, exposing the artifact graph and instruction loader functionality to users and agents. Commands are top-level for fluid UX and implemented in isolation for easy removal.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Status Command
|
||||
The system SHALL display artifact completion status for a change.
|
||||
|
||||
#### Scenario: Show status with all states
|
||||
- **WHEN** user runs `openspec status --change <id>`
|
||||
- **THEN** the system displays each artifact with status indicator:
|
||||
- `[x]` for completed artifacts
|
||||
- `[ ]` for ready artifacts
|
||||
- `[-]` for blocked artifacts (with missing dependencies listed)
|
||||
|
||||
#### Scenario: Status shows completion summary
|
||||
- **WHEN** user runs `openspec status --change <id>`
|
||||
- **THEN** output includes completion percentage and count (e.g., "2/4 artifacts complete")
|
||||
|
||||
#### Scenario: Status JSON output
|
||||
- **WHEN** user runs `openspec status --change <id> --json`
|
||||
- **THEN** the system outputs JSON with changeName, schemaName, isComplete, and artifacts array
|
||||
|
||||
#### Scenario: Missing change parameter
|
||||
- **WHEN** user runs `openspec status` without `--change`
|
||||
- **THEN** the system displays an error with list of available changes
|
||||
|
||||
#### Scenario: Unknown change
|
||||
- **WHEN** user runs `openspec status --change unknown-id`
|
||||
- **THEN** the system displays an error indicating the change does not exist
|
||||
|
||||
### Requirement: Next Command
|
||||
The system SHALL show which artifacts are ready to be created.
|
||||
|
||||
#### Scenario: Show ready artifacts
|
||||
- **WHEN** user runs `openspec next --change <id>`
|
||||
- **THEN** the system lists artifacts whose dependencies are all satisfied
|
||||
|
||||
#### Scenario: No artifacts ready
|
||||
- **WHEN** all artifacts are either completed or blocked
|
||||
- **THEN** the system indicates no artifacts are ready (with explanation)
|
||||
|
||||
#### Scenario: All artifacts complete
|
||||
- **WHEN** all artifacts in the change are completed
|
||||
- **THEN** the system indicates the change is complete
|
||||
|
||||
#### Scenario: Next JSON output
|
||||
- **WHEN** user runs `openspec next --change <id> --json`
|
||||
- **THEN** the system outputs JSON array of ready artifact IDs
|
||||
|
||||
### Requirement: Instructions Command
|
||||
The system SHALL output enriched instructions for creating an artifact.
|
||||
|
||||
#### Scenario: Show enriched instructions
|
||||
- **WHEN** user runs `openspec instructions <artifact> --change <id>`
|
||||
- **THEN** the system outputs:
|
||||
- Artifact metadata (ID, output path, description)
|
||||
- Template content
|
||||
- Dependency status (done/missing)
|
||||
- Unlocked artifacts (what becomes available after completion)
|
||||
|
||||
#### Scenario: Instructions JSON output
|
||||
- **WHEN** user runs `openspec instructions <artifact> --change <id> --json`
|
||||
- **THEN** the system outputs JSON matching ArtifactInstructions interface
|
||||
|
||||
#### Scenario: Unknown artifact
|
||||
- **WHEN** user runs `openspec instructions unknown-artifact --change <id>`
|
||||
- **THEN** the system displays an error listing valid artifact IDs for the schema
|
||||
|
||||
#### Scenario: Artifact with unmet dependencies
|
||||
- **WHEN** user requests instructions for a blocked artifact
|
||||
- **THEN** the system displays instructions with a warning about missing dependencies
|
||||
|
||||
### Requirement: Templates Command
|
||||
The system SHALL show resolved template paths for all artifacts in a schema.
|
||||
|
||||
#### Scenario: List template paths with default schema
|
||||
- **WHEN** user runs `openspec templates`
|
||||
- **THEN** the system displays each artifact with its resolved template path using the default schema
|
||||
|
||||
#### Scenario: List template paths with custom schema
|
||||
- **WHEN** user runs `openspec templates --schema tdd`
|
||||
- **THEN** the system displays template paths for the specified schema
|
||||
|
||||
#### Scenario: Templates JSON output
|
||||
- **WHEN** user runs `openspec templates --json`
|
||||
- **THEN** the system outputs JSON mapping artifact IDs to template paths
|
||||
|
||||
#### Scenario: Template resolution source
|
||||
- **WHEN** displaying template paths
|
||||
- **THEN** the system indicates whether each template is from user override or package built-in
|
||||
|
||||
### Requirement: New Change Command
|
||||
The system SHALL create new change directories with validation.
|
||||
|
||||
#### Scenario: Create valid change
|
||||
- **WHEN** user runs `openspec new change add-feature`
|
||||
- **THEN** the system creates `openspec/changes/add-feature/` directory
|
||||
|
||||
#### Scenario: Invalid change name
|
||||
- **WHEN** user runs `openspec new change "Add Feature"` with invalid name
|
||||
- **THEN** the system displays validation error with guidance
|
||||
|
||||
#### Scenario: Duplicate change name
|
||||
- **WHEN** user runs `openspec new change existing-change` for an existing change
|
||||
- **THEN** the system displays an error indicating the change already exists
|
||||
|
||||
#### Scenario: Create with description
|
||||
- **WHEN** user runs `openspec new change add-feature --description "Add new feature"`
|
||||
- **THEN** the system creates the change directory with description in README.md
|
||||
|
||||
### Requirement: Schema Selection
|
||||
The system SHALL support custom schema selection for workflow commands.
|
||||
|
||||
#### Scenario: Default schema
|
||||
- **WHEN** user runs workflow commands without `--schema`
|
||||
- **THEN** the system uses the "spec-driven" schema
|
||||
|
||||
#### Scenario: Custom schema
|
||||
- **WHEN** user runs `openspec status --change <id> --schema tdd`
|
||||
- **THEN** the system uses the specified schema for artifact graph
|
||||
|
||||
#### Scenario: Unknown schema
|
||||
- **WHEN** user specifies an unknown schema
|
||||
- **THEN** the system displays an error listing available schemas
|
||||
|
||||
### Requirement: Output Formatting
|
||||
The system SHALL provide consistent output formatting.
|
||||
|
||||
#### Scenario: Color output
|
||||
- **WHEN** terminal supports colors
|
||||
- **THEN** status indicators use colors: green (done), yellow (ready), red (blocked)
|
||||
|
||||
#### Scenario: No color output
|
||||
- **WHEN** `--no-color` flag is used or NO_COLOR environment variable is set
|
||||
- **THEN** output uses text-only indicators without ANSI colors
|
||||
|
||||
#### Scenario: Progress indication
|
||||
- **WHEN** loading change state takes time
|
||||
- **THEN** the system displays a spinner during loading
|
||||
|
||||
### Requirement: Experimental Isolation
|
||||
The system SHALL implement artifact workflow commands in isolation for easy removal.
|
||||
|
||||
#### Scenario: Single file implementation
|
||||
- **WHEN** artifact workflow feature is implemented
|
||||
- **THEN** all commands are in `src/commands/artifact-workflow.ts`
|
||||
|
||||
#### Scenario: Help text marking
|
||||
- **WHEN** user runs `--help` on any artifact workflow command
|
||||
- **THEN** help text indicates the command is experimental
|
||||
@@ -0,0 +1,48 @@
|
||||
## 1. Core Command Implementation
|
||||
|
||||
- [x] 1.1 Create `src/commands/artifact-workflow.ts` with all commands
|
||||
- [x] 1.2 Implement `status` command with text output
|
||||
- [x] 1.3 Implement `next` command with text output
|
||||
- [x] 1.4 Implement `instructions` command with text output
|
||||
- [x] 1.5 Implement `templates` command with text output
|
||||
- [x] 1.6 Implement `new change` subcommand using createChange()
|
||||
|
||||
## 2. CLI Registration
|
||||
|
||||
- [x] 2.1 Register `status` command in `src/cli/index.ts`
|
||||
- [x] 2.2 Register `next` command in `src/cli/index.ts`
|
||||
- [x] 2.3 Register `instructions` command in `src/cli/index.ts`
|
||||
- [x] 2.4 Register `templates` command in `src/cli/index.ts`
|
||||
- [x] 2.5 Register `new` command group with `change` subcommand
|
||||
|
||||
## 3. Output Formatting
|
||||
|
||||
- [x] 3.1 Add `--json` flag support to all commands
|
||||
- [x] 3.2 Add color-coded status indicators (done/ready/blocked)
|
||||
- [x] 3.3 Add progress spinner for loading operations
|
||||
- [x] 3.4 Support `--no-color` flag
|
||||
|
||||
## 4. Error Handling
|
||||
|
||||
- [x] 4.1 Handle missing `--change` parameter with helpful error
|
||||
- [x] 4.2 Handle unknown change names with list of available changes
|
||||
- [x] 4.3 Handle unknown artifact names with valid options
|
||||
- [x] 4.4 Handle schema resolution errors
|
||||
|
||||
## 5. Options and Flags
|
||||
|
||||
- [x] 5.1 Add `--schema` option for custom schema selection
|
||||
- [x] 5.2 Add `--description` option to `new change` command
|
||||
- [x] 5.3 Ensure options follow existing CLI patterns
|
||||
|
||||
## 6. Testing
|
||||
|
||||
- [x] 6.1 Add smoke tests for each command
|
||||
- [x] 6.2 Test error cases (missing change, unknown artifact)
|
||||
- [x] 6.3 Test JSON output format
|
||||
- [x] 6.4 Test with different schemas
|
||||
|
||||
## 7. Documentation
|
||||
|
||||
- [x] 7.1 Add help text for all commands marked as "Experimental"
|
||||
- [ ] 7.2 Update AGENTS.md with new commands (post-archive)
|
||||
@@ -0,0 +1,151 @@
|
||||
# Design: Unify Change State Model
|
||||
|
||||
## Overview
|
||||
|
||||
This change fixes two bugs with minimal disruption to the existing system:
|
||||
|
||||
1. **View bug**: Empty changes incorrectly shown as "Completed"
|
||||
2. **Artifact workflow bug**: Commands fail on scaffolded changes
|
||||
|
||||
## Key Design Decision: Two Systems, Two Purposes
|
||||
|
||||
The task-based and artifact-based systems serve **different purposes** and should coexist:
|
||||
|
||||
| System | Purpose | Used By |
|
||||
|--------|---------|---------|
|
||||
| **Task Progress** | Track implementation work | `openspec view`, `openspec list` |
|
||||
| **Artifact Progress** | Track planning/spec work | `openspec status`, `openspec next` |
|
||||
|
||||
We do NOT merge these systems. Instead, we fix each to work correctly in its domain.
|
||||
|
||||
## Change 1: Fix View Command
|
||||
|
||||
### Current Logic (Buggy)
|
||||
|
||||
```typescript
|
||||
// view.ts line 90
|
||||
if (progress.total === 0 || progress.completed === progress.total) {
|
||||
completed.push({ name: entry.name });
|
||||
}
|
||||
```
|
||||
|
||||
Problem: `total === 0` means "no tasks defined yet", not "all tasks done".
|
||||
|
||||
### New Logic
|
||||
|
||||
```typescript
|
||||
if (progress.total === 0) {
|
||||
draft.push({ name: entry.name });
|
||||
} else if (progress.completed === progress.total) {
|
||||
completed.push({ name: entry.name });
|
||||
} else {
|
||||
active.push({ name: entry.name, progress });
|
||||
}
|
||||
```
|
||||
|
||||
### View Output Change
|
||||
|
||||
**Before:**
|
||||
```
|
||||
Completed Changes
|
||||
─────────────────
|
||||
✓ add-feature (all tasks done - correct)
|
||||
✓ test-workflow (no tasks - WRONG)
|
||||
```
|
||||
|
||||
**After:**
|
||||
```
|
||||
Draft Changes
|
||||
─────────────────
|
||||
○ test-workflow (no tasks yet)
|
||||
|
||||
Active Changes
|
||||
─────────────────
|
||||
◉ add-scaffold [████░░░░] 3/7 tasks
|
||||
|
||||
Completed Changes
|
||||
─────────────────
|
||||
✓ add-feature (all tasks done)
|
||||
```
|
||||
|
||||
## Change 2: Fix Artifact Workflow Discovery
|
||||
|
||||
### Current Logic (Buggy)
|
||||
|
||||
```typescript
|
||||
// artifact-workflow.ts - validateChangeExists()
|
||||
const activeChanges = await getActiveChangeIds(projectRoot);
|
||||
if (!activeChanges.includes(changeName)) {
|
||||
throw new Error(`Change '${changeName}' not found...`);
|
||||
}
|
||||
```
|
||||
|
||||
Problem: `getActiveChangeIds()` requires `proposal.md`, but artifact workflow should work on empty directories to help create the first artifact.
|
||||
|
||||
### New Logic
|
||||
|
||||
```typescript
|
||||
async function validateChangeExists(changeName: string, projectRoot: string): Promise<string> {
|
||||
const changePath = path.join(projectRoot, 'openspec', 'changes', changeName);
|
||||
|
||||
// Check directory existence directly, not proposal.md
|
||||
if (!fs.existsSync(changePath) || !fs.statSync(changePath).isDirectory()) {
|
||||
// List available changes for helpful error message
|
||||
const entries = await fs.promises.readdir(
|
||||
path.join(projectRoot, 'openspec', 'changes'),
|
||||
{ withFileTypes: true }
|
||||
);
|
||||
const available = entries
|
||||
.filter(e => e.isDirectory() && e.name !== 'archive' && !e.name.startsWith('.'))
|
||||
.map(e => e.name);
|
||||
|
||||
if (available.length === 0) {
|
||||
throw new Error('No changes found. Create one with: openspec new change <name>');
|
||||
}
|
||||
throw new Error(`Change '${changeName}' not found. Available:\n ${available.join('\n ')}`);
|
||||
}
|
||||
|
||||
return changeName;
|
||||
}
|
||||
```
|
||||
|
||||
### Behavior Change
|
||||
|
||||
```bash
|
||||
# Before
|
||||
$ openspec new change foo
|
||||
$ openspec status --change foo
|
||||
Error: Change 'foo' not found.
|
||||
|
||||
# After
|
||||
$ openspec new change foo
|
||||
$ openspec status --change foo
|
||||
Change: foo
|
||||
Progress: 0/4 artifacts complete
|
||||
|
||||
[ ] proposal
|
||||
[-] specs (blocked by: proposal)
|
||||
[-] design (blocked by: proposal)
|
||||
[-] tasks (blocked by: specs, design)
|
||||
```
|
||||
|
||||
## What Stays the Same
|
||||
|
||||
1. **`getActiveChangeIds()`** - Still requires `proposal.md` (used by validate, show)
|
||||
2. **`getArchivedChangeIds()`** - Unchanged
|
||||
3. **Active/Completed semantics** - Still based on task checkboxes
|
||||
4. **Validation** - Still requires `proposal.md` to have something to validate
|
||||
|
||||
## File Changes
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `src/core/view.ts` | Add draft category, fix completion logic |
|
||||
| `src/commands/artifact-workflow.ts` | Update `validateChangeExists()` to use directory existence |
|
||||
| `test/commands/artifact-workflow.test.ts` | Add tests for scaffolded changes |
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
1. **Unit test**: `validateChangeExists()` with scaffolded change
|
||||
2. **View test**: Verify three categories render correctly
|
||||
3. **Manual test**: Full workflow from `new change` → `status` → `view`
|
||||
@@ -0,0 +1,101 @@
|
||||
# Proposal: Unify Change State Model
|
||||
|
||||
## Problem Statement
|
||||
|
||||
Two bugs create inconsistent behavior when working with changes:
|
||||
|
||||
### Bug 1: Empty changes shown as "Completed" in view
|
||||
|
||||
```typescript
|
||||
// view.ts line 90
|
||||
if (progress.total === 0 || progress.completed === progress.total) {
|
||||
completed.push({ name: entry.name }); // BUG: total === 0 ≠ completed
|
||||
}
|
||||
```
|
||||
|
||||
Result: `openspec new change foo && openspec view` shows `foo` as "Completed" when it has no content.
|
||||
|
||||
### Bug 2: Artifact workflow commands can't find scaffolded changes
|
||||
|
||||
```typescript
|
||||
// item-discovery.ts - getActiveChangeIds()
|
||||
const proposalPath = path.join(changesPath, entry.name, 'proposal.md');
|
||||
await fs.access(proposalPath); // Only returns changes WITH proposal.md
|
||||
```
|
||||
|
||||
Result: `openspec status --change foo` says "not found" even though the directory exists.
|
||||
|
||||
## Root Cause
|
||||
|
||||
The system conflates two different concepts:
|
||||
|
||||
| Concept | Question | Source of Truth |
|
||||
|---------|----------|-----------------|
|
||||
| **Planning Progress** | Are all spec documents created? | File existence (ArtifactGraph) |
|
||||
| **Implementation Progress** | Is the coding work done? | Task checkboxes (tasks.md) |
|
||||
|
||||
## Proposed Solution
|
||||
|
||||
### Fix 1: Add "Draft" state to view command
|
||||
|
||||
Keep Active/Completed with their existing meanings, but fix the bug:
|
||||
|
||||
| State | Criteria | Meaning |
|
||||
|-------|----------|---------|
|
||||
| **Draft** | No tasks.md OR `tasks.total === 0` | Still planning |
|
||||
| **Active** | `tasks.total > 0` AND `completed < total` | Implementing |
|
||||
| **Completed** | `tasks.total > 0` AND `completed === total` | Done |
|
||||
|
||||
### Fix 2: Artifact workflow uses directory existence
|
||||
|
||||
Update `validateChangeExists()` to check if the directory exists, not if `proposal.md` exists. This allows the artifact workflow to guide users through creating their first artifact.
|
||||
|
||||
### Keep existing discovery functions
|
||||
|
||||
`getActiveChangeIds()` continues to require `proposal.md` for backward compatibility with validation and other commands.
|
||||
|
||||
## What Changes
|
||||
|
||||
| Command | Before | After |
|
||||
|---------|--------|-------|
|
||||
| `openspec view` | Empty = "Completed" | Empty = "Draft" |
|
||||
| `openspec status --change X` | Requires proposal.md | Works on any directory |
|
||||
| `openspec validate X` | Requires proposal.md | Unchanged (still requires it) |
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
### Minimal Breaking Change
|
||||
|
||||
1. **`openspec view` output**: Empty changes move from "Completed" section to new "Draft" section
|
||||
|
||||
### Non-Breaking
|
||||
|
||||
- Active/Completed semantics unchanged (still task-based)
|
||||
- `getActiveChangeIds()` unchanged
|
||||
- `openspec validate` unchanged
|
||||
- Archived changes unaffected
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Merging task-based and artifact-based progress (they serve different purposes)
|
||||
- Changing what "Completed" means (it stays = all tasks done)
|
||||
- Adding artifact progress to view command (separate enhancement)
|
||||
- Shell tab completions for artifact workflow commands (not yet registered)
|
||||
|
||||
## Related Commands Analysis
|
||||
|
||||
| Command | Uses `getActiveChangeIds()` | Should include scaffolded? | Change needed? |
|
||||
|---------|-----------------------------|-----------------------------|----------------|
|
||||
| `openspec view` | No (reads dirs directly) | Yes → Draft section | **Yes** |
|
||||
| `openspec list` | No (reads dirs directly) | Yes (shows "No tasks") | No |
|
||||
| `openspec status/next/instructions` | Yes | Yes | **Yes** |
|
||||
| `openspec validate` | Yes | No (can't validate empty) | No |
|
||||
| `openspec show` | Yes | No (nothing to show) | No |
|
||||
| Tab completions | Yes | Future enhancement | No |
|
||||
|
||||
## Success Criteria
|
||||
|
||||
1. `openspec new change foo && openspec view` shows `foo` in "Draft" section
|
||||
2. `openspec new change foo && openspec status --change foo` works
|
||||
3. Changes with all tasks done still show as "Completed"
|
||||
4. All existing tests pass
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
# cli-artifact-workflow Specification Delta
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Status Command
|
||||
|
||||
The system SHALL display artifact completion status for a change, including scaffolded (empty) changes.
|
||||
|
||||
> **Fixes bug**: Previously required `proposal.md` to exist via `getActiveChangeIds()`.
|
||||
|
||||
#### Scenario: Show status with all states
|
||||
|
||||
- **WHEN** user runs `openspec status --change <id>`
|
||||
- **THEN** the system displays each artifact with status indicator:
|
||||
- `[x]` for completed artifacts
|
||||
- `[ ]` for ready artifacts
|
||||
- `[-]` for blocked artifacts (with missing dependencies listed)
|
||||
|
||||
#### Scenario: Status shows completion summary
|
||||
|
||||
- **WHEN** user runs `openspec status --change <id>`
|
||||
- **THEN** output includes completion percentage and count (e.g., "2/4 artifacts complete")
|
||||
|
||||
#### Scenario: Status JSON output
|
||||
|
||||
- **WHEN** user runs `openspec status --change <id> --json`
|
||||
- **THEN** the system outputs JSON with changeName, schemaName, isComplete, and artifacts array
|
||||
|
||||
#### Scenario: Status on scaffolded change
|
||||
|
||||
- **WHEN** user runs `openspec status --change <id>` on a change with no artifacts
|
||||
- **THEN** system displays all artifacts with their status
|
||||
- **AND** root artifacts (no dependencies) show as ready `[ ]`
|
||||
- **AND** dependent artifacts show as blocked `[-]`
|
||||
|
||||
#### Scenario: Missing change parameter
|
||||
|
||||
- **WHEN** user runs `openspec status` without `--change`
|
||||
- **THEN** the system displays an error with list of available changes
|
||||
- **AND** includes scaffolded changes (directories without proposal.md)
|
||||
|
||||
#### Scenario: Unknown change
|
||||
|
||||
- **WHEN** user runs `openspec status --change unknown-id`
|
||||
- **AND** directory `openspec/changes/unknown-id/` does not exist
|
||||
- **THEN** the system displays an error listing all available change directories
|
||||
|
||||
### Requirement: Next Command
|
||||
|
||||
The system SHALL show which artifacts are ready to be created, including for scaffolded changes.
|
||||
|
||||
#### Scenario: Show ready artifacts
|
||||
|
||||
- **WHEN** user runs `openspec next --change <id>`
|
||||
- **THEN** the system lists artifacts whose dependencies are all satisfied
|
||||
|
||||
#### Scenario: No artifacts ready
|
||||
|
||||
- **WHEN** all artifacts are either completed or blocked
|
||||
- **THEN** the system indicates no artifacts are ready (with explanation)
|
||||
|
||||
#### Scenario: All artifacts complete
|
||||
|
||||
- **WHEN** all artifacts in the change are completed
|
||||
- **THEN** the system indicates the change is complete
|
||||
|
||||
#### Scenario: Next JSON output
|
||||
|
||||
- **WHEN** user runs `openspec next --change <id> --json`
|
||||
- **THEN** the system outputs JSON array of ready artifact IDs
|
||||
|
||||
#### Scenario: Next on scaffolded change
|
||||
|
||||
- **WHEN** user runs `openspec next --change <id>` on a change with no artifacts
|
||||
- **THEN** system shows root artifacts (e.g., "proposal") as ready to create
|
||||
|
||||
### Requirement: Instructions Command
|
||||
|
||||
The system SHALL output enriched instructions for creating an artifact, including for scaffolded changes.
|
||||
|
||||
#### Scenario: Show enriched instructions
|
||||
|
||||
- **WHEN** user runs `openspec instructions <artifact> --change <id>`
|
||||
- **THEN** the system outputs:
|
||||
- Artifact metadata (ID, output path, description)
|
||||
- Template content
|
||||
- Dependency status (done/missing)
|
||||
- Unlocked artifacts (what becomes available after completion)
|
||||
|
||||
#### Scenario: Instructions JSON output
|
||||
|
||||
- **WHEN** user runs `openspec instructions <artifact> --change <id> --json`
|
||||
- **THEN** the system outputs JSON matching ArtifactInstructions interface
|
||||
|
||||
#### Scenario: Unknown artifact
|
||||
|
||||
- **WHEN** user runs `openspec instructions unknown-artifact --change <id>`
|
||||
- **THEN** the system displays an error listing valid artifact IDs for the schema
|
||||
|
||||
#### Scenario: Artifact with unmet dependencies
|
||||
|
||||
- **WHEN** user requests instructions for a blocked artifact
|
||||
- **THEN** the system displays instructions with a warning about missing dependencies
|
||||
|
||||
#### Scenario: Instructions on scaffolded change
|
||||
|
||||
- **WHEN** user runs `openspec instructions proposal --change <id>` on a scaffolded change
|
||||
- **THEN** system outputs template and metadata for creating the proposal
|
||||
- **AND** does not require any artifacts to already exist
|
||||
@@ -0,0 +1,60 @@
|
||||
# cli-view Specification Delta
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Draft Changes Display
|
||||
|
||||
The dashboard SHALL display changes without tasks in a separate "Draft" section.
|
||||
|
||||
#### Scenario: Draft changes listing
|
||||
|
||||
- **WHEN** there are changes with no tasks.md or zero tasks defined
|
||||
- **THEN** system shows them in a "Draft Changes" section
|
||||
- **AND** uses a distinct indicator (e.g., `○`) to show draft status
|
||||
|
||||
#### Scenario: Draft section ordering
|
||||
|
||||
- **WHEN** multiple draft changes exist
|
||||
- **THEN** system sorts them alphabetically by name
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Completed Changes Display
|
||||
|
||||
The dashboard SHALL list completed changes in a separate section, only showing changes with ALL tasks completed.
|
||||
|
||||
> **Fixes bug**: Previously, changes with `total === 0` were incorrectly shown as completed.
|
||||
|
||||
#### Scenario: Completed changes listing
|
||||
|
||||
- **WHEN** there are changes with `tasks.total > 0` AND `tasks.completed === tasks.total`
|
||||
- **THEN** system shows them with checkmark indicators in a dedicated section
|
||||
|
||||
#### Scenario: Mixed completion states
|
||||
|
||||
- **WHEN** some changes are complete and others active
|
||||
- **THEN** system separates them into appropriate sections
|
||||
|
||||
#### Scenario: Empty changes not completed
|
||||
|
||||
- **WHEN** a change has no tasks.md or zero tasks defined
|
||||
- **THEN** system does NOT show it in "Completed Changes" section
|
||||
- **AND** shows it in "Draft Changes" section instead
|
||||
|
||||
### Requirement: Summary Section
|
||||
|
||||
The dashboard SHALL display a summary section with key project metrics, including draft change count.
|
||||
|
||||
#### Scenario: Complete summary display
|
||||
|
||||
- **WHEN** dashboard is rendered with specs and changes
|
||||
- **THEN** system shows total number of specifications and requirements
|
||||
- **AND** shows number of draft changes
|
||||
- **AND** shows number of active changes in progress
|
||||
- **AND** shows number of completed changes
|
||||
- **AND** shows overall task progress percentage
|
||||
|
||||
#### Scenario: Empty project summary
|
||||
|
||||
- **WHEN** no specs or changes exist
|
||||
- **THEN** summary shows zero counts for all metrics
|
||||
@@ -0,0 +1,25 @@
|
||||
# Tasks: Unify Change State Model
|
||||
|
||||
## Phase 1: Fix Artifact Workflow Discovery
|
||||
|
||||
- [x] Update `validateChangeExists()` in `artifact-workflow.ts` to check directory existence instead of using `getActiveChangeIds()`
|
||||
- [x] Update error message to list all change directories (not just those with proposal.md)
|
||||
- [x] Add test for `openspec status --change <scaffolded-change>`
|
||||
- [x] Add test for `openspec next --change <scaffolded-change>`
|
||||
- [x] Add test for `openspec instructions proposal --change <scaffolded-change>`
|
||||
|
||||
## Phase 2: Fix View Command
|
||||
|
||||
- [x] Update `getChangesData()` in `view.ts` to return three categories: draft, active, completed
|
||||
- [x] Fix completion logic: `total === 0` → draft, not completed
|
||||
- [x] Add "Draft Changes" section to dashboard rendering
|
||||
- [x] Update summary to include draft count
|
||||
- [x] Add test for draft changes appearing correctly in view
|
||||
|
||||
## Phase 3: Cleanup and Validation
|
||||
|
||||
- [x] Clean up test changes (`test-workflow`, `test-workflow-2`)
|
||||
- [x] Run full test suite
|
||||
- [x] Manual test: `openspec new change foo && openspec status --change foo`
|
||||
- [x] Manual test: `openspec new change foo && openspec view` shows foo in Draft
|
||||
- [x] Validate with `openspec validate unify-change-state-model --strict`
|
||||
@@ -0,0 +1,105 @@
|
||||
# Delta for CLI Init
|
||||
|
||||
## MODIFIED Requirements
|
||||
### Requirement: Slash Command Configuration
|
||||
The init command SHALL generate slash command files for supported editors using shared templates.
|
||||
|
||||
#### Scenario: Generating slash commands for Antigravity
|
||||
- **WHEN** the user selects Antigravity during initialization
|
||||
- **THEN** create `.agent/workflows/openspec-proposal.md`, `.agent/workflows/openspec-apply.md`, and `.agent/workflows/openspec-archive.md`
|
||||
- **AND** ensure each file begins with YAML frontmatter that contains only a `description: <stage summary>` field followed by the shared OpenSpec workflow instructions wrapped in managed markers
|
||||
- **AND** populate the workflow body with the same proposal/apply/archive guidance used for other tools so Antigravity behaves like Windsurf while pointing to the `.agent/workflows/` directory
|
||||
|
||||
#### Scenario: Generating slash commands for Claude Code
|
||||
- **WHEN** the user selects Claude Code during initialization
|
||||
- **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for CodeBuddy Code
|
||||
- **WHEN** the user selects CodeBuddy Code during initialization
|
||||
- **THEN** create `.codebuddy/commands/openspec/proposal.md`, `.codebuddy/commands/openspec/apply.md`, and `.codebuddy/commands/openspec/archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Cline
|
||||
- **WHEN** the user selects Cline during initialization
|
||||
- **THEN** create `.clinerules/openspec-proposal.md`, `.clinerules/openspec-apply.md`, and `.clinerules/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** include Cline-specific Markdown heading frontmatter
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Crush
|
||||
- **WHEN** the user selects Crush during initialization
|
||||
- **THEN** create `.crush/commands/openspec/proposal.md`, `.crush/commands/openspec/apply.md`, and `.crush/commands/openspec/archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** include Crush-specific frontmatter with OpenSpec category and tags
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Cursor
|
||||
- **WHEN** the user selects Cursor during initialization
|
||||
- **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Factory Droid
|
||||
- **WHEN** the user selects Factory Droid during initialization
|
||||
- **THEN** create `.factory/commands/openspec-proposal.md`, `.factory/commands/openspec-apply.md`, and `.factory/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates that include Factory-compatible YAML frontmatter for the `description` and `argument-hint` fields
|
||||
- **AND** include the `$ARGUMENTS` placeholder in the template body so droid receives any user-supplied input
|
||||
- **AND** wrap the generated content in OpenSpec managed markers so `openspec update` can safely refresh the commands
|
||||
|
||||
#### Scenario: Generating slash commands for OpenCode
|
||||
- **WHEN** the user selects OpenCode during initialization
|
||||
- **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Windsurf
|
||||
- **WHEN** the user selects Windsurf during initialization
|
||||
- **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Kilo Code
|
||||
- **WHEN** the user selects Kilo Code during initialization
|
||||
- **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Codex
|
||||
- **WHEN** the user selects Codex during initialization
|
||||
- **THEN** create global prompt files at `~/.codex/prompts/openspec-proposal.md`, `~/.codex/prompts/openspec-apply.md`, and `~/.codex/prompts/openspec-archive.md` (or under `$CODEX_HOME/prompts` if set)
|
||||
- **AND** populate each file from shared templates that map the first numbered placeholder (`$1`) to the primary user input (e.g., change identifier or question text)
|
||||
- **AND** wrap the generated content in OpenSpec markers so `openspec update` can refresh the prompts without touching surrounding custom notes
|
||||
|
||||
#### Scenario: Generating slash commands for GitHub Copilot
|
||||
- **WHEN** the user selects GitHub Copilot during initialization
|
||||
- **THEN** create `.github/prompts/openspec-proposal.prompt.md`, `.github/prompts/openspec-apply.prompt.md`, and `.github/prompts/openspec-archive.prompt.md`
|
||||
- **AND** populate each file with YAML frontmatter containing a `description` field that summarizes the workflow stage
|
||||
- **AND** include `$ARGUMENTS` placeholder to capture user input
|
||||
- **AND** wrap the shared template body with OpenSpec markers so `openspec update` can refresh the content
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Gemini CLI
|
||||
- **WHEN** the user selects Gemini CLI during initialization
|
||||
- **THEN** create `.gemini/commands/openspec/proposal.toml`, `.gemini/commands/openspec/apply.toml`, and `.gemini/commands/openspec/archive.toml`
|
||||
- **AND** populate each file as TOML that sets a stage-specific `description = "<summary>"` and a multi-line `prompt = """` block with the shared OpenSpec template
|
||||
- **AND** wrap the OpenSpec managed markers (`<!-- OPENSPEC:START -->` / `<!-- OPENSPEC:END -->`) inside the `prompt` value so `openspec update` can safely refresh the body between markers without touching the TOML framing
|
||||
- **AND** ensure the slash-command copy matches the existing proposal/apply/archive templates used by other tools
|
||||
|
||||
#### Scenario: Generating slash commands for iFlow CLI
|
||||
- **WHEN** the user selects iFlow CLI during initialization
|
||||
- **THEN** create `.iflow/commands/openspec-proposal.md`, `.iflow/commands/openspec-apply.md`, and `.iflow/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** include YAML frontmatter with `name`, `id`, `category`, and `description` fields for each command
|
||||
- **AND** wrap the generated content in OpenSpec managed markers so `openspec update` can safely refresh the commands
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for RooCode
|
||||
- **WHEN** the user selects RooCode during initialization
|
||||
- **THEN** create `.roo/commands/openspec-proposal.md`, `.roo/commands/openspec-apply.md`, and `.roo/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** include simple Markdown headings (e.g., `# OpenSpec: Proposal`) without YAML frontmatter
|
||||
- **AND** wrap the generated content in OpenSpec managed markers where applicable so `openspec update` can safely refresh the commands
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
@@ -0,0 +1,92 @@
|
||||
# Delta for CLI Update
|
||||
|
||||
## MODIFIED Requirements
|
||||
### Requirement: Slash Command Updates
|
||||
The update command SHALL refresh existing slash command files for configured tools without creating new ones, and ensure the OpenCode archive command accepts change ID arguments.
|
||||
|
||||
#### Scenario: Updating slash commands for Antigravity
|
||||
- **WHEN** `.agent/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh the OpenSpec-managed portion of each file so the workflow copy matches other tools while preserving the existing single-field `description` frontmatter
|
||||
- **AND** skip creating any missing workflow files during update, mirroring the behavior for Windsurf and other IDEs
|
||||
|
||||
#### Scenario: Updating slash commands for Claude Code
|
||||
- **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for CodeBuddy Code
|
||||
- **WHEN** `.codebuddy/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Cline
|
||||
- **WHEN** `.clinerules/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** include Cline-specific Markdown heading frontmatter
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Crush
|
||||
- **WHEN** `.crush/commands/` contains `openspec/proposal.md`, `openspec/apply.md`, and `openspec/archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** include Crush-specific frontmatter with OpenSpec category and tags
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Cursor
|
||||
- **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Factory Droid
|
||||
- **WHEN** `.factory/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using the shared Factory templates that include YAML frontmatter for the `description` and `argument-hint` fields
|
||||
- **AND** ensure the template body retains the `$ARGUMENTS` placeholder so user input keeps flowing into droid
|
||||
- **AND** update only the content inside the OpenSpec managed markers, leaving any unmanaged notes untouched
|
||||
- **AND** skip creating missing files during update
|
||||
|
||||
#### Scenario: Updating slash commands for OpenCode
|
||||
- **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
- **AND** ensure the archive command includes `$ARGUMENTS` placeholder in frontmatter for accepting change ID arguments
|
||||
|
||||
#### Scenario: Updating slash commands for Windsurf
|
||||
- **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates wrapped in OpenSpec markers
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
- **AND** skip creating missing files (the update command only refreshes what already exists)
|
||||
|
||||
#### Scenario: Updating slash commands for Kilo Code
|
||||
- **WHEN** `.kilocode/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates wrapped in OpenSpec markers
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
- **AND** skip creating missing files (the update command only refreshes what already exists)
|
||||
|
||||
#### Scenario: Updating slash commands for Codex
|
||||
- **GIVEN** the global Codex prompt directory contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **WHEN** a user runs `openspec update`
|
||||
- **THEN** refresh each file using the shared slash-command templates (including placeholder guidance)
|
||||
- **AND** preserve any unmanaged content outside the OpenSpec marker block
|
||||
- **AND** skip creation when a Codex prompt file is missing
|
||||
|
||||
#### Scenario: Updating slash commands for GitHub Copilot
|
||||
- **WHEN** `.github/prompts/` contains `openspec-proposal.prompt.md`, `openspec-apply.prompt.md`, and `openspec-archive.prompt.md`
|
||||
- **THEN** refresh each file using shared templates while preserving the YAML frontmatter
|
||||
- **AND** update only the OpenSpec-managed block between markers
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Gemini CLI
|
||||
- **WHEN** `.gemini/commands/openspec/` contains `proposal.toml`, `apply.toml`, and `archive.toml`
|
||||
- **THEN** refresh the body of each file using the shared proposal/apply/archive templates
|
||||
- **AND** replace only the content between `<!-- OPENSPEC:START -->` and `<!-- OPENSPEC:END -->` markers inside the `prompt = """` block so the TOML framing (`description`, `prompt`) stays intact
|
||||
- **AND** skip creating any missing `.toml` files during update; only pre-existing Gemini commands are refreshed
|
||||
|
||||
#### Scenario: Updating slash commands for iFlow CLI
|
||||
- **WHEN** `.iflow/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** preserve the YAML frontmatter with `name`, `id`, `category`, and `description` fields
|
||||
- **AND** update only the OpenSpec-managed block between markers
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Missing slash command file
|
||||
- **WHEN** a tool lacks a slash command file
|
||||
- **THEN** do not create a new file during update
|
||||
+1
-1
@@ -8,6 +8,6 @@ The Cline implementation was architecturally incorrect. According to Cline's off
|
||||
- **BREAKING**: Existing Cline users will need to re-run `openspec init` to get the corrected workflow files
|
||||
|
||||
## Impact
|
||||
- Affected specs: cli-init (corrected Cline workflow paths)
|
||||
- Affected specs: cli-init, cli-update (corrected Cline workflow paths)
|
||||
- Affected code: `src/core/configurators/slash/cline.ts`, test files, README.md
|
||||
- Modified files: `.clinerules/workflows/openspec-*.md` (moved from `.clinerules/openspec-*.md`)
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
# Delta for CLI Init
|
||||
|
||||
## MODIFIED Requirements
|
||||
### Requirement: Slash Command Configuration
|
||||
The init command SHALL generate slash command files for supported editors using shared templates.
|
||||
|
||||
#### Scenario: Generating slash commands for Antigravity
|
||||
- **WHEN** the user selects Antigravity during initialization
|
||||
- **THEN** create `.agent/workflows/openspec-proposal.md`, `.agent/workflows/openspec-apply.md`, and `.agent/workflows/openspec-archive.md`
|
||||
- **AND** ensure each file begins with YAML frontmatter that contains only a `description: <stage summary>` field followed by the shared OpenSpec workflow instructions wrapped in managed markers
|
||||
- **AND** populate the workflow body with the same proposal/apply/archive guidance used for other tools so Antigravity behaves like Windsurf while pointing to the `.agent/workflows/` directory
|
||||
|
||||
#### Scenario: Generating slash commands for Claude Code
|
||||
- **WHEN** the user selects Claude Code during initialization
|
||||
- **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for CodeBuddy Code
|
||||
- **WHEN** the user selects CodeBuddy Code during initialization
|
||||
- **THEN** create `.codebuddy/commands/openspec/proposal.md`, `.codebuddy/commands/openspec/apply.md`, and `.codebuddy/commands/openspec/archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Cline
|
||||
- **WHEN** the user selects Cline during initialization
|
||||
- **THEN** create `.clinerules/workflows/openspec-proposal.md`, `.clinerules/workflows/openspec-apply.md`, and `.clinerules/workflows/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** include Cline-specific Markdown heading frontmatter
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Crush
|
||||
- **WHEN** the user selects Crush during initialization
|
||||
- **THEN** create `.crush/commands/openspec/proposal.md`, `.crush/commands/openspec/apply.md`, and `.crush/commands/openspec/archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** include Crush-specific frontmatter with OpenSpec category and tags
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Cursor
|
||||
- **WHEN** the user selects Cursor during initialization
|
||||
- **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Factory Droid
|
||||
- **WHEN** the user selects Factory Droid during initialization
|
||||
- **THEN** create `.factory/commands/openspec-proposal.md`, `.factory/commands/openspec-apply.md`, and `.factory/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates that include Factory-compatible YAML frontmatter for the `description` and `argument-hint` fields
|
||||
- **AND** include the `$ARGUMENTS` placeholder in the template body so droid receives any user-supplied input
|
||||
- **AND** wrap the generated content in OpenSpec managed markers so `openspec update` can safely refresh the commands
|
||||
|
||||
#### Scenario: Generating slash commands for OpenCode
|
||||
- **WHEN** the user selects OpenCode during initialization
|
||||
- **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Windsurf
|
||||
- **WHEN** the user selects Windsurf during initialization
|
||||
- **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Kilo Code
|
||||
- **WHEN** the user selects Kilo Code during initialization
|
||||
- **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Codex
|
||||
- **WHEN** the user selects Codex during initialization
|
||||
- **THEN** create global prompt files at `~/.codex/prompts/openspec-proposal.md`, `~/.codex/prompts/openspec-apply.md`, and `~/.codex/prompts/openspec-archive.md` (or under `$CODEX_HOME/prompts` if set)
|
||||
- **AND** populate each file from shared templates that map the first numbered placeholder (`$1`) to the primary user input (e.g., change identifier or question text)
|
||||
- **AND** wrap the generated content in OpenSpec markers so `openspec update` can refresh the prompts without touching surrounding custom notes
|
||||
|
||||
#### Scenario: Generating slash commands for GitHub Copilot
|
||||
- **WHEN** the user selects GitHub Copilot during initialization
|
||||
- **THEN** create `.github/prompts/openspec-proposal.prompt.md`, `.github/prompts/openspec-apply.prompt.md`, and `.github/prompts/openspec-archive.prompt.md`
|
||||
- **AND** populate each file with YAML frontmatter containing a `description` field that summarizes the workflow stage
|
||||
- **AND** include `$ARGUMENTS` placeholder to capture user input
|
||||
- **AND** wrap the shared template body with OpenSpec markers so `openspec update` can refresh the content
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Gemini CLI
|
||||
- **WHEN** the user selects Gemini CLI during initialization
|
||||
- **THEN** create `.gemini/commands/openspec/proposal.toml`, `.gemini/commands/openspec/apply.toml`, and `.gemini/commands/openspec/archive.toml`
|
||||
- **AND** populate each file as TOML that sets a stage-specific `description = "<summary>"` and a multi-line `prompt = """` block with the shared OpenSpec template
|
||||
- **AND** wrap the OpenSpec managed markers (`<!-- OPENSPEC:START -->` / `<!-- OPENSPEC:END -->`) inside the `prompt` value so `openspec update` can safely refresh the body between markers without touching the TOML framing
|
||||
- **AND** ensure the slash-command copy matches the existing proposal/apply/archive templates used by other tools
|
||||
|
||||
#### Scenario: Generating slash commands for iFlow CLI
|
||||
- **WHEN** the user selects iFlow CLI during initialization
|
||||
- **THEN** create `.iflow/commands/openspec-proposal.md`, `.iflow/commands/openspec-apply.md`, and `.iflow/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** include YAML frontmatter with `name`, `id`, `category`, and `description` fields for each command
|
||||
- **AND** wrap the generated content in OpenSpec managed markers so `openspec update` can safely refresh the commands
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for RooCode
|
||||
- **WHEN** the user selects RooCode during initialization
|
||||
- **THEN** create `.roo/commands/openspec-proposal.md`, `.roo/commands/openspec-apply.md`, and `.roo/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** include simple Markdown headings (e.g., `# OpenSpec: Proposal`) without YAML frontmatter
|
||||
- **AND** wrap the generated content in OpenSpec managed markers where applicable so `openspec update` can safely refresh the commands
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
# Delta for CLI Update
|
||||
|
||||
## MODIFIED Requirements
|
||||
### Requirement: Slash Command Updates
|
||||
The update command SHALL refresh existing slash command files for configured tools without creating new ones, and ensure the OpenCode archive command accepts change ID arguments.
|
||||
|
||||
#### Scenario: Updating slash commands for Antigravity
|
||||
- **WHEN** `.agent/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh the OpenSpec-managed portion of each file so the workflow copy matches other tools while preserving the existing single-field `description` frontmatter
|
||||
- **AND** skip creating any missing workflow files during update, mirroring the behavior for Windsurf and other IDEs
|
||||
|
||||
#### Scenario: Updating slash commands for Claude Code
|
||||
- **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for CodeBuddy Code
|
||||
- **WHEN** `.codebuddy/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Cline
|
||||
- **WHEN** `.clinerules/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** include Cline-specific Markdown heading frontmatter
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Crush
|
||||
- **WHEN** `.crush/commands/` contains `openspec/proposal.md`, `openspec/apply.md`, and `openspec/archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** include Crush-specific frontmatter with OpenSpec category and tags
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Cursor
|
||||
- **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Factory Droid
|
||||
- **WHEN** `.factory/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using the shared Factory templates that include YAML frontmatter for the `description` and `argument-hint` fields
|
||||
- **AND** ensure the template body retains the `$ARGUMENTS` placeholder so user input keeps flowing into droid
|
||||
- **AND** update only the content inside the OpenSpec managed markers, leaving any unmanaged notes untouched
|
||||
- **AND** skip creating missing files during update
|
||||
|
||||
#### Scenario: Updating slash commands for OpenCode
|
||||
- **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
- **AND** ensure the archive command includes `$ARGUMENTS` placeholder in frontmatter for accepting change ID arguments
|
||||
|
||||
#### Scenario: Updating slash commands for Windsurf
|
||||
- **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates wrapped in OpenSpec markers
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
- **AND** skip creating missing files (the update command only refreshes what already exists)
|
||||
|
||||
#### Scenario: Updating slash commands for Kilo Code
|
||||
- **WHEN** `.kilocode/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates wrapped in OpenSpec markers
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
- **AND** skip creating missing files (the update command only refreshes what already exists)
|
||||
|
||||
#### Scenario: Updating slash commands for Codex
|
||||
- **GIVEN** the global Codex prompt directory contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **WHEN** a user runs `openspec update`
|
||||
- **THEN** refresh each file using the shared slash-command templates (including placeholder guidance)
|
||||
- **AND** preserve any unmanaged content outside the OpenSpec marker block
|
||||
- **AND** skip creation when a Codex prompt file is missing
|
||||
|
||||
#### Scenario: Updating slash commands for GitHub Copilot
|
||||
- **WHEN** `.github/prompts/` contains `openspec-proposal.prompt.md`, `openspec-apply.prompt.md`, and `openspec-archive.prompt.md`
|
||||
- **THEN** refresh each file using shared templates while preserving the YAML frontmatter
|
||||
- **AND** update only the OpenSpec-managed block between markers
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Gemini CLI
|
||||
- **WHEN** `.gemini/commands/openspec/` contains `proposal.toml`, `apply.toml`, and `archive.toml`
|
||||
- **THEN** refresh the body of each file using the shared proposal/apply/archive templates
|
||||
- **AND** replace only the content between `<!-- OPENSPEC:START -->` and `<!-- OPENSPEC:END -->` markers inside the `prompt = """` block so the TOML framing (`description`, `prompt`) stays intact
|
||||
- **AND** skip creating any missing `.toml` files during update; only pre-existing Gemini commands are refreshed
|
||||
|
||||
#### Scenario: Updating slash commands for iFlow CLI
|
||||
- **WHEN** `.iflow/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** preserve the YAML frontmatter with `name`, `id`, `category`, and `description` fields
|
||||
- **AND** update only the OpenSpec-managed block between markers
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Missing slash command file
|
||||
- **WHEN** a tool lacks a slash command file
|
||||
- **THEN** do not create a new file during update
|
||||
@@ -0,0 +1,26 @@
|
||||
## Why
|
||||
|
||||
With per-change schema metadata in place (see `add-per-change-schema-metadata`), agents can now create changes with different workflow schemas. However, the agent skills are still hardcoded to `spec-driven` artifacts and don't offer schema selection to users.
|
||||
|
||||
## What Changes
|
||||
|
||||
**Scope: Experimental artifact workflow agent skills**
|
||||
|
||||
**Depends on:** `add-per-change-schema-metadata` (must be implemented first)
|
||||
|
||||
- Update `openspec-new-change` skill to prompt user for schema selection
|
||||
- Update `openspec-continue-change` skill to work with any schema's artifacts
|
||||
- Update `openspec-apply-change` skill to handle schema-specific task structures
|
||||
- Add schema descriptions to help users choose appropriate workflow
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Modified Capabilities
|
||||
- `cli-artifact-workflow`: Agent skills support dynamic schema selection
|
||||
|
||||
## Impact
|
||||
|
||||
- **Affected code**: `src/core/templates/skill-templates.ts`
|
||||
- **User experience**: Users can choose TDD, spec-driven, or future workflows when starting a change
|
||||
- **Agent behavior**: Skills read artifact list from schema rather than hardcoding
|
||||
- **Backward compatible**: Default remains `spec-driven` if user doesn't choose
|
||||
@@ -0,0 +1,32 @@
|
||||
## Prerequisites
|
||||
|
||||
- [x] 0.1 Implement `add-per-change-schema-metadata` change first
|
||||
|
||||
## 1. Schema Discovery
|
||||
|
||||
- [x] 1.1 Add CLI command or helper to list schemas with descriptions (for agent use)
|
||||
- [x] 1.2 Ensure `openspec templates --schema <name>` returns artifact list for any schema
|
||||
|
||||
## 2. Update New Change Skill
|
||||
|
||||
- [x] 2.1 Add schema selection prompt using AskUserQuestion tool
|
||||
- [x] 2.2 Present available schemas with descriptions (spec-driven, tdd, etc.)
|
||||
- [x] 2.3 Pass selected schema to `openspec new change --schema <name>`
|
||||
- [x] 2.4 Update output to show which schema/workflow was selected
|
||||
|
||||
## 3. Update Continue Change Skill
|
||||
|
||||
- [x] 3.1 Remove hardcoded artifact references (proposal, specs, design, tasks)
|
||||
- [x] 3.2 Read artifact list dynamically from `openspec status --json`
|
||||
- [x] 3.3 Adjust artifact creation guidelines to be schema-agnostic
|
||||
- [x] 3.4 Handle schema-specific artifact types (e.g., TDD's `tests` artifact)
|
||||
|
||||
## 4. Update Apply Change Skill
|
||||
|
||||
- [x] 4.1 Make task detection work with different schema structures
|
||||
- [x] 4.2 Adjust context file reading for schema-specific artifacts
|
||||
|
||||
## 5. Documentation
|
||||
|
||||
- [x] 5.1 Add schema descriptions to help text or skill instructions
|
||||
- [x] 5.2 Document when to use each schema (TDD for bug fixes, spec-driven for features, etc.)
|
||||
@@ -0,0 +1,147 @@
|
||||
## Context
|
||||
|
||||
The experimental artifact workflow supports multiple schemas (`spec-driven`, `tdd`), but schema selection must be passed on every command. This creates friction for agents and users.
|
||||
|
||||
We need a lightweight metadata file to persist the schema choice per change.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Store schema choice once at change creation
|
||||
- Auto-detect schema in experimental workflow commands
|
||||
- Maintain backward compatibility (no metadata = default)
|
||||
- Validate metadata with Zod schema
|
||||
|
||||
**Non-Goals:**
|
||||
- Migrate existing changes (they use default)
|
||||
- Extend to legacy commands
|
||||
- Store additional metadata beyond schema (keep minimal for now)
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision: Zod Schema Design
|
||||
|
||||
The metadata file (`.openspec.yaml`) will be validated with this Zod schema:
|
||||
|
||||
```typescript
|
||||
// src/core/artifact-graph/types.ts (or new metadata.ts)
|
||||
|
||||
import { z } from 'zod';
|
||||
import { listSchemas } from './resolver.js';
|
||||
|
||||
/**
|
||||
* Schema for per-change metadata stored in .openspec.yaml
|
||||
*/
|
||||
export const ChangeMetadataSchema = z.object({
|
||||
// Required: which workflow schema this change uses
|
||||
schema: z.string().min(1, { message: 'schema is required' }).refine(
|
||||
(val) => listSchemas().includes(val),
|
||||
(val) => ({ message: `Unknown schema '${val}'. Available: ${listSchemas().join(', ')}` })
|
||||
),
|
||||
|
||||
// Optional: creation timestamp (ISO date string)
|
||||
created: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, {
|
||||
message: 'created must be YYYY-MM-DD format'
|
||||
}).optional(),
|
||||
});
|
||||
|
||||
export type ChangeMetadata = z.infer<typeof ChangeMetadataSchema>;
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- `schema` is required and validated against available schemas at parse time
|
||||
- `created` is optional, ISO date format for consistency
|
||||
- Minimal fields - can extend later without breaking existing files
|
||||
- Follows existing codebase pattern (see `ArtifactSchema`, `SchemaYamlSchema`)
|
||||
|
||||
### Decision: File Location and Format
|
||||
|
||||
**Location:** `openspec/changes/<name>/.openspec.yaml`
|
||||
|
||||
**Format:**
|
||||
```yaml
|
||||
schema: tdd
|
||||
created: 2025-01-05
|
||||
```
|
||||
|
||||
**Alternatives considered:**
|
||||
- `change.yaml` - less hidden, but clutters directory
|
||||
- Frontmatter in `proposal.md` - couples to proposal existence
|
||||
- `openspec.json` - YAML matches existing schema files
|
||||
|
||||
### Decision: Read/Write Functions
|
||||
|
||||
```typescript
|
||||
// src/utils/change-metadata.ts
|
||||
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import * as yaml from 'yaml';
|
||||
import { ChangeMetadataSchema, type ChangeMetadata } from '../core/artifact-graph/types.js';
|
||||
|
||||
const METADATA_FILENAME = '.openspec.yaml';
|
||||
|
||||
export function writeChangeMetadata(
|
||||
changeDir: string,
|
||||
metadata: ChangeMetadata
|
||||
): void {
|
||||
// Validate before writing
|
||||
const validated = ChangeMetadataSchema.parse(metadata);
|
||||
const content = yaml.stringify(validated);
|
||||
fs.writeFileSync(path.join(changeDir, METADATA_FILENAME), content);
|
||||
}
|
||||
|
||||
export function readChangeMetadata(
|
||||
changeDir: string
|
||||
): ChangeMetadata | null {
|
||||
const metaPath = path.join(changeDir, METADATA_FILENAME);
|
||||
|
||||
if (!fs.existsSync(metaPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(metaPath, 'utf-8');
|
||||
const parsed = yaml.parse(content);
|
||||
|
||||
// Validate and return (throws ZodError if invalid)
|
||||
return ChangeMetadataSchema.parse(parsed);
|
||||
}
|
||||
```
|
||||
|
||||
### Decision: Schema Resolution Order
|
||||
|
||||
When determining which schema to use:
|
||||
|
||||
1. **Explicit `--schema` flag** (highest priority - user override)
|
||||
2. **`.openspec.yaml` metadata** (persisted choice)
|
||||
3. **Default `spec-driven`** (fallback)
|
||||
|
||||
```typescript
|
||||
function resolveSchemaForChange(
|
||||
changeDir: string,
|
||||
explicitSchema?: string
|
||||
): string {
|
||||
if (explicitSchema) return explicitSchema;
|
||||
|
||||
const metadata = readChangeMetadata(changeDir);
|
||||
if (metadata?.schema) return metadata.schema;
|
||||
|
||||
return 'spec-driven';
|
||||
}
|
||||
```
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **Extra file per change** → Minimal overhead, hidden file
|
||||
- **YAML parsing dependency** → Already using `yaml` package for schema files
|
||||
- **Schema validation at read time** → Fail fast with clear error if corrupted
|
||||
|
||||
## Migration Plan
|
||||
|
||||
No migration needed:
|
||||
- Existing changes without `.openspec.yaml` continue to work (use default)
|
||||
- New changes created with `openspec new change --schema X` get metadata file
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Should `openspec new change` prompt for schema interactively if not specified? (Leaning no - default is fine)
|
||||
@@ -0,0 +1,29 @@
|
||||
## Why
|
||||
|
||||
Currently, the schema (workflow type) must be passed via `--schema` flag on every experimental workflow command. This is repetitive and error-prone. Agents have no way to know which schema a change uses, so they default to `spec-driven` and cannot leverage alternative workflows like `tdd`.
|
||||
|
||||
## What Changes
|
||||
|
||||
**Scope: Experimental artifact workflow only** (`openspec new change`, `openspec status`, `openspec instructions`, `openspec templates`)
|
||||
|
||||
- Store schema choice in `.openspec.yaml` metadata file when creating a change via `openspec new change`
|
||||
- Auto-detect schema from metadata in experimental workflow commands
|
||||
- Make `--schema` flag optional (override only, metadata takes precedence)
|
||||
- Add `--schema` option to `openspec new change` command
|
||||
|
||||
**Not affected**: Legacy commands (`openspec validate`, `openspec archive`, `openspec list`, `openspec show`)
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `change-metadata`: Reading/writing per-change metadata files
|
||||
|
||||
### Modified Capabilities
|
||||
- `cli-artifact-workflow`: Commands auto-detect schema from change metadata
|
||||
|
||||
## Impact
|
||||
|
||||
- **Affected code**: `src/utils/change-utils.ts`, `src/core/artifact-graph/instruction-loader.ts`, `src/commands/artifact-workflow.ts`
|
||||
- **Agent skills**: Can be simplified - no longer need to pass schema explicitly
|
||||
- **Backward compatible**: Changes without `.openspec.yaml` fall back to `spec-driven` default
|
||||
- **Isolation**: All changes contained within experimental workflow code; legacy commands untouched
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Change Metadata
|
||||
|
||||
The system SHALL store and validate per-change metadata in `.openspec.yaml` files using a Zod schema.
|
||||
|
||||
#### Scenario: Metadata file created with new change
|
||||
|
||||
- **WHEN** user runs `openspec new change add-feature --schema tdd`
|
||||
- **THEN** the system creates `.openspec.yaml` in the change directory
|
||||
- **AND** the file contains `schema: tdd` and `created: <YYYY-MM-DD>`
|
||||
|
||||
#### Scenario: Metadata validated on read
|
||||
|
||||
- **WHEN** the system reads `.openspec.yaml`
|
||||
- **AND** the `schema` field references an unknown schema
|
||||
- **THEN** the system displays a validation error listing available schemas
|
||||
|
||||
#### Scenario: Metadata schema validation
|
||||
|
||||
- **WHEN** `.openspec.yaml` contains invalid YAML or missing required fields
|
||||
- **THEN** the system displays a Zod validation error with details
|
||||
|
||||
#### Scenario: Missing metadata file
|
||||
|
||||
- **WHEN** a change directory has no `.openspec.yaml` file
|
||||
- **THEN** the system falls back to the default schema (`spec-driven`)
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: New Change Command
|
||||
|
||||
The system SHALL create new change directories with validation and optional schema metadata.
|
||||
|
||||
#### Scenario: Create valid change
|
||||
|
||||
- **WHEN** user runs `openspec new change add-feature`
|
||||
- **THEN** the system creates `openspec/changes/add-feature/` directory
|
||||
- **AND** creates `.openspec.yaml` with `schema: spec-driven` (default)
|
||||
|
||||
#### Scenario: Create change with schema
|
||||
|
||||
- **WHEN** user runs `openspec new change add-feature --schema tdd`
|
||||
- **THEN** the system creates `openspec/changes/add-feature/` directory
|
||||
- **AND** creates `.openspec.yaml` with `schema: tdd`
|
||||
|
||||
#### Scenario: Invalid schema on create
|
||||
|
||||
- **WHEN** user runs `openspec new change add-feature --schema unknown`
|
||||
- **THEN** the system displays an error listing available schemas
|
||||
- **AND** does not create the change directory
|
||||
|
||||
#### Scenario: Invalid change name
|
||||
|
||||
- **WHEN** user runs `openspec new change "Add Feature"` with invalid name
|
||||
- **THEN** the system displays validation error with guidance
|
||||
|
||||
#### Scenario: Duplicate change name
|
||||
|
||||
- **WHEN** user runs `openspec new change existing-change` for an existing change
|
||||
- **THEN** the system displays an error indicating the change already exists
|
||||
|
||||
#### Scenario: Create with description
|
||||
|
||||
- **WHEN** user runs `openspec new change add-feature --description "Add new feature"`
|
||||
- **THEN** the system creates the change directory with description in README.md
|
||||
|
||||
### Requirement: Schema Selection
|
||||
|
||||
The system SHALL support custom schema selection for workflow commands, with automatic detection from change metadata.
|
||||
|
||||
#### Scenario: Schema auto-detected from metadata
|
||||
|
||||
- **WHEN** user runs `openspec status --change <id>` without `--schema`
|
||||
- **AND** the change has `.openspec.yaml` with `schema: tdd`
|
||||
- **THEN** the system uses the `tdd` schema
|
||||
|
||||
#### Scenario: Explicit schema overrides metadata
|
||||
|
||||
- **WHEN** user runs `openspec status --change <id> --schema spec-driven`
|
||||
- **AND** the change has `.openspec.yaml` with `schema: tdd`
|
||||
- **THEN** the system uses `spec-driven` (explicit flag wins)
|
||||
|
||||
#### Scenario: Default schema fallback
|
||||
|
||||
- **WHEN** user runs workflow commands without `--schema`
|
||||
- **AND** the change has no `.openspec.yaml` file
|
||||
- **THEN** the system uses the "spec-driven" schema
|
||||
|
||||
#### Scenario: Custom schema via flag
|
||||
|
||||
- **WHEN** user runs `openspec status --change <id> --schema tdd`
|
||||
- **THEN** the system uses the specified schema for artifact graph
|
||||
|
||||
#### Scenario: Unknown schema
|
||||
|
||||
- **WHEN** user specifies an unknown schema
|
||||
- **THEN** the system displays an error listing available schemas
|
||||
@@ -0,0 +1,29 @@
|
||||
## 1. Zod Schema and Types
|
||||
|
||||
- [x] 1.1 Add `ChangeMetadataSchema` Zod schema to `src/core/artifact-graph/types.ts`
|
||||
- [x] 1.2 Export `ChangeMetadata` type inferred from schema
|
||||
|
||||
## 2. Core Metadata Functions
|
||||
|
||||
- [x] 2.1 Create `src/utils/change-metadata.ts` with `writeChangeMetadata()` function
|
||||
- [x] 2.2 Add `readChangeMetadata()` function with Zod validation
|
||||
- [x] 2.3 Update `createChange()` to accept optional `schema` param and write metadata
|
||||
|
||||
## 3. Auto-Detection in Instruction Loader
|
||||
|
||||
- [x] 3.1 Modify `loadChangeContext()` to read schema from `.openspec.yaml`
|
||||
- [x] 3.2 Make `schemaName` parameter optional (fall back to metadata, then default)
|
||||
|
||||
## 4. CLI Updates
|
||||
|
||||
- [x] 4.1 Add `--schema <name>` option to `openspec new change` command
|
||||
- [x] 4.2 Verify existing commands (`status`, `instructions`) work with auto-detection
|
||||
|
||||
## 5. Tests
|
||||
|
||||
- [x] 5.1 Test `ChangeMetadataSchema` validates correctly (valid/invalid cases)
|
||||
- [x] 5.2 Test `writeChangeMetadata()` creates valid YAML
|
||||
- [x] 5.3 Test `readChangeMetadata()` parses and validates schema
|
||||
- [x] 5.4 Test `loadChangeContext()` auto-detects schema from metadata
|
||||
- [x] 5.5 Test fallback to default when no metadata exists
|
||||
- [x] 5.6 Test `--schema` flag overrides metadata
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-01-06
|
||||
@@ -0,0 +1,77 @@
|
||||
## Context
|
||||
|
||||
Currently, delta specs are only applied to main specs when running `openspec archive`. This bundles two concerns:
|
||||
1. Applying spec changes (delta → main)
|
||||
2. Archiving the change (move to archive folder)
|
||||
|
||||
Users want flexibility to sync specs earlier, especially when iterating. The archive command already contains the reconciliation logic in `buildUpdatedSpec()`.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Decouple spec syncing from archiving
|
||||
- Provide `/opsx:sync` skill for agents to sync specs on demand
|
||||
- Keep operation idempotent (safe to run multiple times)
|
||||
|
||||
**Non-Goals:**
|
||||
- Tracking whether specs have been synced (no state)
|
||||
- Changing archive behavior (it will continue to apply specs)
|
||||
- Supporting partial application (all deltas sync together)
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. Reuse existing reconciliation logic
|
||||
|
||||
**Decision**: Extract `buildUpdatedSpec()` logic from `ArchiveCommand` into a shared module.
|
||||
|
||||
**Rationale**: The archive command already implements delta parsing and application. Rather than duplicate, we extract and reuse.
|
||||
|
||||
**Alternatives considered**:
|
||||
- Duplicate logic in new command (rejected: maintenance burden)
|
||||
- Have sync call archive with flags (rejected: coupling)
|
||||
|
||||
### 2. No state tracking
|
||||
|
||||
**Decision**: Don't track whether specs have been synced. Each invocation reads delta and main specs, reconciles.
|
||||
|
||||
**Rationale**:
|
||||
- Idempotent operations don't need state
|
||||
- Avoids sync issues between flag and reality
|
||||
- Simpler implementation and mental model
|
||||
|
||||
**Alternatives considered**:
|
||||
- Track `specsSynced: true` in `.openspec.yaml` (rejected: unnecessary complexity)
|
||||
- Store snapshot of synced deltas (rejected: over-engineering)
|
||||
|
||||
### 3. Agent-driven approach (no CLI command)
|
||||
|
||||
**Decision**: The `/opsx:sync` skill is fully agent-driven - the agent reads delta specs and directly edits main specs.
|
||||
|
||||
**Rationale**:
|
||||
- Allows intelligent merging (add scenarios without copying entire requirements)
|
||||
- Delta represents *intent*, not wholesale replacement
|
||||
- More flexible and natural editing workflow
|
||||
- Archive still uses programmatic merge (for finalized changes)
|
||||
|
||||
### 4. Archive behavior unchanged
|
||||
|
||||
**Decision**: Archive continues to apply specs as part of its flow. If specs are already reconciled, the operation is a no-op.
|
||||
|
||||
**Rationale**: Backward compatibility. Users who don't use `/opsx:sync` get the same experience.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
**[Risk] Multiple changes modify same spec**
|
||||
→ Last to sync wins. Same as today with archive. Users should coordinate or use sequential archives.
|
||||
|
||||
**[Risk] User syncs specs then continues editing deltas**
|
||||
→ Running `/opsx:sync` again reconciles. Idempotent design handles this.
|
||||
|
||||
**[Trade-off] No undo mechanism**
|
||||
→ Users can `git checkout` main specs if needed. Explicit undo command is out of scope.
|
||||
|
||||
## Implementation Approach
|
||||
|
||||
1. Extract spec application logic from `ArchiveCommand.buildUpdatedSpec()` into `src/core/specs-apply.ts`
|
||||
2. Add skill template for `/opsx:sync` in `skill-templates.ts`
|
||||
3. Register skill in managed skills
|
||||
@@ -0,0 +1,32 @@
|
||||
## Why
|
||||
|
||||
Spec application is currently bundled with archive - users must run `openspec archive` to apply delta specs to main specs. This couples two distinct concerns (applying specs vs. archiving the change) and forces users to wait until they're "done" to see main specs updated. Users want the flexibility to sync specs earlier in the workflow while iterating.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add `/opsx:sync` skill that syncs delta specs to main specs as a standalone action
|
||||
- The operation is idempotent - safe to run multiple times, agent reconciles main specs to match deltas
|
||||
- Archive continues to work as today (applies specs if not already reconciled, then moves to archive)
|
||||
- No new state tracking - the agent reads delta and main specs, reconciles on each run
|
||||
- Agent-driven approach allows intelligent merging (partial updates, adding scenarios)
|
||||
|
||||
**Workflow becomes:**
|
||||
```
|
||||
/opsx:new → /opsx:continue → /opsx:apply → archive
|
||||
│
|
||||
└── /opsx:sync (optional, anytime)
|
||||
```
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `specs-sync-skill`: Skill template for `/opsx:sync` command that reconciles main specs with delta specs
|
||||
|
||||
### Modified Capabilities
|
||||
- None (agent-driven, no CLI command needed)
|
||||
|
||||
## Impact
|
||||
|
||||
- **Skills**: New `openspec-sync-specs` skill in `skill-templates.ts`
|
||||
- **Archive**: No changes needed - already does reconciliation, will continue to work
|
||||
- **Agent workflow**: Users gain flexibility to sync specs before archive
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Specs Sync Skill
|
||||
The system SHALL provide an `/opsx:sync` skill that syncs delta specs from a change to the main specs.
|
||||
|
||||
#### Scenario: Sync delta specs to main specs
|
||||
- **WHEN** agent executes `/opsx:sync` with a change name
|
||||
- **THEN** the agent reads delta specs from `openspec/changes/<name>/specs/`
|
||||
- **AND** reads corresponding main specs from `openspec/specs/`
|
||||
- **AND** reconciles main specs to match what the deltas describe
|
||||
|
||||
#### Scenario: Idempotent operation
|
||||
- **WHEN** agent executes `/opsx:sync` multiple times on the same change
|
||||
- **THEN** the result is the same as running it once
|
||||
- **AND** no duplicate requirements are created
|
||||
|
||||
#### Scenario: Change selection prompt
|
||||
- **WHEN** agent executes `/opsx:sync` without specifying a change
|
||||
- **THEN** the agent prompts user to select from available changes
|
||||
- **AND** shows changes that have delta specs
|
||||
|
||||
### Requirement: Delta Reconciliation Logic
|
||||
The agent SHALL reconcile main specs with delta specs using the delta operation headers.
|
||||
|
||||
#### Scenario: ADDED requirements
|
||||
- **WHEN** delta contains `## ADDED Requirements` with a requirement
|
||||
- **AND** the requirement does not exist in main spec
|
||||
- **THEN** add the requirement to main spec
|
||||
|
||||
#### Scenario: ADDED requirement already exists
|
||||
- **WHEN** delta contains `## ADDED Requirements` with a requirement
|
||||
- **AND** a requirement with the same name already exists in main spec
|
||||
- **THEN** update the existing requirement to match the delta version
|
||||
|
||||
#### Scenario: MODIFIED requirements
|
||||
- **WHEN** delta contains `## MODIFIED Requirements` with a requirement
|
||||
- **AND** the requirement exists in main spec
|
||||
- **THEN** replace the requirement in main spec with the delta version
|
||||
|
||||
#### Scenario: REMOVED requirements
|
||||
- **WHEN** delta contains `## REMOVED Requirements` with a requirement name
|
||||
- **AND** the requirement exists in main spec
|
||||
- **THEN** remove the requirement from main spec
|
||||
|
||||
#### Scenario: RENAMED requirements
|
||||
- **WHEN** delta contains `## RENAMED Requirements` with FROM:/TO: format
|
||||
- **AND** the FROM requirement exists in main spec
|
||||
- **THEN** rename the requirement to the TO name
|
||||
|
||||
#### Scenario: New capability spec
|
||||
- **WHEN** delta spec exists for a capability not in main specs
|
||||
- **THEN** create new main spec file at `openspec/specs/<capability>/spec.md`
|
||||
|
||||
### Requirement: Skill Output
|
||||
The skill SHALL provide clear feedback on what was synced.
|
||||
|
||||
#### Scenario: Show synced changes
|
||||
- **WHEN** reconciliation completes successfully
|
||||
- **THEN** display summary of changes per capability:
|
||||
- Number of requirements added
|
||||
- Number of requirements modified
|
||||
- Number of requirements removed
|
||||
- Number of requirements renamed
|
||||
|
||||
#### Scenario: No changes needed
|
||||
- **WHEN** main specs already match delta specs
|
||||
- **THEN** display "Specs already in sync - no changes needed"
|
||||
@@ -0,0 +1,40 @@
|
||||
## Tasks
|
||||
|
||||
### Core Implementation
|
||||
|
||||
- [x] Extract spec application logic from `ArchiveCommand` into `src/core/specs-apply.ts`
|
||||
- Move `buildUpdatedSpec()`, `findSpecUpdates()`, `writeUpdatedSpec()` to shared module
|
||||
- Keep `ArchiveCommand` importing from the new module
|
||||
- Ensure all validation logic is preserved
|
||||
|
||||
### Skill Template
|
||||
|
||||
- [x] Add `getSyncSpecsSkillTemplate()` function in `src/core/templates/skill-templates.ts`
|
||||
- Skill name: `openspec-sync-specs`
|
||||
- Description: Sync delta specs to main specs
|
||||
- **Agent-driven**: Instructions for agent to read deltas and edit main specs directly
|
||||
|
||||
- [x] Add `/opsx:sync` slash command template in `skill-templates.ts`
|
||||
- Mirror the skill template for slash command format
|
||||
- **Agent-driven**: No CLI command, agent does the merge
|
||||
|
||||
### Registration
|
||||
|
||||
- [x] Register skill in managed skills (via `artifact-experimental-setup`)
|
||||
- Add to skill list with appropriate metadata
|
||||
- Ensure it appears in setup output
|
||||
|
||||
### Design Decision
|
||||
|
||||
**Why agent-driven instead of CLI-driven?**
|
||||
|
||||
The programmatic merge operates at requirement-level granularity:
|
||||
- MODIFIED requires copying ALL scenarios, not just the changed ones
|
||||
- If agent forgets a scenario, it gets deleted
|
||||
- Delta specs become bloated with copied content
|
||||
|
||||
Agent-driven approach:
|
||||
- Agent can apply partial updates (add a scenario without copying others)
|
||||
- Delta represents *intent*, not wholesale replacement
|
||||
- More flexible and natural editing workflow
|
||||
- Archive still uses programmatic merge (for finalized changes)
|
||||
@@ -0,0 +1,138 @@
|
||||
## Why
|
||||
|
||||
The `generateApplyInstructions` function is hardcoded to check for `spec-driven` artifacts (`proposal.md`, `specs/`, `design.md`, `tasks.md`). If a user selects a different schema like `tdd`, the apply instructions are meaningless - they check for files that don't exist in that schema.
|
||||
|
||||
This blocks the experimental workflow from supporting multiple schemas properly.
|
||||
|
||||
## What Changes
|
||||
|
||||
**Scope: Experimental artifact workflow** (`openspec instructions apply`)
|
||||
|
||||
**Depends on:** `add-per-change-schema-metadata` (to know which schema a change uses)
|
||||
|
||||
- Make `generateApplyInstructions` read artifact definitions from the schema
|
||||
- Dynamically determine which artifacts exist based on schema
|
||||
- Define when a change becomes "implementable" (see Design Decision below)
|
||||
- Generate schema-appropriate context files and instructions
|
||||
|
||||
## Design Decision: When is a change implementable?
|
||||
|
||||
This is the key question. Different approaches:
|
||||
|
||||
### Option A: Explicit `apply` artifact in schema
|
||||
|
||||
Add a field to mark which artifact is the "implementation gate":
|
||||
|
||||
```yaml
|
||||
artifacts:
|
||||
- id: tasks
|
||||
generates: tasks.md
|
||||
apply: true # ← This artifact triggers apply mode
|
||||
```
|
||||
|
||||
**Pros:** Explicit, flexible
|
||||
**Cons:** Another field to maintain, what if multiple artifacts are `apply: true`?
|
||||
|
||||
### Option B: Leaf artifacts are implementable
|
||||
|
||||
The artifact(s) with no dependents (nothing depends on them) are the apply target.
|
||||
|
||||
- `spec-driven`: `tasks` is a leaf → apply = execute tasks
|
||||
- `tdd`: `docs` is a leaf → but that doesn't make sense for TDD...
|
||||
|
||||
**Pros:** No extra schema field, derived from graph
|
||||
**Cons:** Doesn't match TDD semantics (implementation is the action, not docs)
|
||||
|
||||
### Option C: Schema-level `apply_phase` definition
|
||||
|
||||
Add a top-level field to the schema:
|
||||
|
||||
```yaml
|
||||
name: spec-driven
|
||||
apply_phase:
|
||||
requires: [tasks] # Must exist before apply
|
||||
tracks: tasks.md # File with checkboxes to track
|
||||
instruction: "Work through tasks, mark complete as you go"
|
||||
```
|
||||
|
||||
```yaml
|
||||
name: tdd
|
||||
apply_phase:
|
||||
requires: [tests] # Must have tests before implementing
|
||||
tracks: null # No checkbox tracking - just make tests pass
|
||||
instruction: "Run tests, implement until green, refactor"
|
||||
```
|
||||
|
||||
**Pros:** Full flexibility, schema controls its own apply semantics
|
||||
**Cons:** More complex schema format
|
||||
|
||||
### Option D: Convention-based (artifact ID matching)
|
||||
|
||||
If artifact ID is `tasks` or `implementation`, it's the apply target.
|
||||
|
||||
**Pros:** Simple, no schema changes
|
||||
**Cons:** Brittle, doesn't work for custom schemas
|
||||
|
||||
### Option E: All artifacts complete → apply available
|
||||
|
||||
Apply becomes available when ALL schema artifacts exist. Implementation is whatever the user does after planning.
|
||||
|
||||
**Pros:** Simple, no schema changes
|
||||
**Cons:** Doesn't guide what "apply" means for different workflows
|
||||
|
||||
---
|
||||
|
||||
## Decision: Add `apply` block to schema.yaml
|
||||
|
||||
Add a top-level `apply` field to schema definitions:
|
||||
|
||||
```yaml
|
||||
name: spec-driven
|
||||
version: 1
|
||||
description: Default OpenSpec workflow
|
||||
|
||||
artifacts:
|
||||
# ... existing artifacts ...
|
||||
|
||||
apply:
|
||||
requires: [tasks] # Artifacts that must exist before apply
|
||||
tracks: tasks.md # File with checkboxes for progress (optional)
|
||||
instruction: | # Guidance shown to agent
|
||||
Read context files, work through pending tasks, mark complete as you go.
|
||||
Pause if you hit blockers or need clarification.
|
||||
```
|
||||
|
||||
```yaml
|
||||
name: tdd
|
||||
version: 1
|
||||
description: Test-driven development workflow
|
||||
|
||||
artifacts:
|
||||
# ... existing artifacts ...
|
||||
|
||||
apply:
|
||||
requires: [tests] # Must have tests before implementing
|
||||
tracks: null # No checkbox tracking
|
||||
instruction: |
|
||||
Run tests to see failures. Implement minimal code to pass each test.
|
||||
Refactor while keeping tests green.
|
||||
```
|
||||
|
||||
**Key properties:**
|
||||
- `requires`: Array of artifact IDs that must exist before apply is available
|
||||
- `tracks`: Path to file with checkboxes (relative to change dir), or `null` if no tracking
|
||||
- `instruction`: Custom guidance for the apply phase
|
||||
|
||||
**Fallback behavior:** Schemas without `apply` block default to "all artifacts must exist"
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Modified Capabilities
|
||||
- `cli-artifact-workflow`: Apply instructions become schema-aware
|
||||
|
||||
## Impact
|
||||
|
||||
- **Affected code**: `src/commands/artifact-workflow.ts` (generateApplyInstructions)
|
||||
- **Schema format**: May need new `apply_phase` field
|
||||
- **Existing schemas**: Need to add apply_phase to `spec-driven` and `tdd`
|
||||
- **Backward compatible**: Schemas without apply_phase can use default behavior
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Schema Apply Block
|
||||
|
||||
The system SHALL support an `apply` block in schema definitions that controls when and how implementation begins.
|
||||
|
||||
#### Scenario: Schema with apply block
|
||||
|
||||
- **WHEN** a schema defines an `apply` block
|
||||
- **THEN** the system uses `apply.requires` to determine which artifacts must exist before apply
|
||||
- **AND** uses `apply.tracks` to identify the file for progress tracking (or null if none)
|
||||
- **AND** uses `apply.instruction` for guidance shown to the agent
|
||||
|
||||
#### Scenario: Schema without apply block
|
||||
|
||||
- **WHEN** a schema has no `apply` block
|
||||
- **THEN** the system requires all artifacts to exist before apply is available
|
||||
- **AND** uses default instruction: "All artifacts complete. Proceed with implementation."
|
||||
|
||||
### Requirement: Apply Instructions Command
|
||||
|
||||
The system SHALL generate schema-aware apply instructions via `openspec instructions apply`.
|
||||
|
||||
#### Scenario: Generate apply instructions
|
||||
|
||||
- **WHEN** user runs `openspec instructions apply --change <id>`
|
||||
- **AND** all required artifacts (per schema's `apply.requires`) exist
|
||||
- **THEN** the system outputs:
|
||||
- Context files from all existing artifacts
|
||||
- Schema-specific instruction text
|
||||
- Progress tracking file path (if `apply.tracks` is set)
|
||||
|
||||
#### Scenario: Apply blocked by missing artifacts
|
||||
|
||||
- **WHEN** user runs `openspec instructions apply --change <id>`
|
||||
- **AND** required artifacts are missing
|
||||
- **THEN** the system indicates apply is blocked
|
||||
- **AND** lists which artifacts must be created first
|
||||
|
||||
#### Scenario: Apply instructions JSON output
|
||||
|
||||
- **WHEN** user runs `openspec instructions apply --change <id> --json`
|
||||
- **THEN** the system outputs JSON with:
|
||||
- `contextFiles`: array of paths to existing artifacts
|
||||
- `instruction`: the apply instruction text
|
||||
- `tracks`: path to progress file or null
|
||||
- `applyRequires`: list of required artifact IDs
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Status Command
|
||||
|
||||
The system SHALL display artifact completion status for a change, including apply readiness.
|
||||
|
||||
#### Scenario: Status JSON includes apply requirements
|
||||
|
||||
- **WHEN** user runs `openspec status --change <id> --json`
|
||||
- **THEN** the system outputs JSON with:
|
||||
- `changeName`, `schemaName`, `isComplete`, `artifacts` array
|
||||
- `applyRequires`: array of artifact IDs needed for apply phase
|
||||
@@ -0,0 +1,35 @@
|
||||
## Prerequisites
|
||||
|
||||
- [x] 0.1 Implement `add-per-change-schema-metadata` first (to auto-detect schema)
|
||||
|
||||
## 1. Schema Format
|
||||
|
||||
- [x] 1.1 Add `ApplyPhaseSchema` Zod schema to `src/core/artifact-graph/types.ts`
|
||||
- [x] 1.2 Update `SchemaYamlSchema` to include optional `apply` field
|
||||
- [x] 1.3 Export `ApplyPhase` type
|
||||
|
||||
## 2. Update Existing Schemas
|
||||
|
||||
- [x] 2.1 Add `apply` block to `schemas/spec-driven/schema.yaml`
|
||||
- [x] 2.2 Add `apply` block to `schemas/tdd/schema.yaml`
|
||||
|
||||
## 3. Refactor generateApplyInstructions
|
||||
|
||||
- [x] 3.1 Load schema via `resolveSchema(schemaName)`
|
||||
- [x] 3.2 Read `apply.requires` to determine required artifacts
|
||||
- [x] 3.3 Check artifact existence dynamically (not hardcoded paths)
|
||||
- [x] 3.4 Use `apply.tracks` for progress tracking (or skip if null)
|
||||
- [x] 3.5 Use `apply.instruction` for the instruction text
|
||||
- [x] 3.6 Build `contextFiles` from all existing artifacts in schema
|
||||
|
||||
## 4. Handle Fallback
|
||||
|
||||
- [x] 4.1 If schema has no `apply` block, require all artifacts to exist
|
||||
- [x] 4.2 Default instruction: "All artifacts complete. Proceed with implementation."
|
||||
|
||||
## 5. Tests
|
||||
|
||||
- [x] 5.1 Test apply instructions with spec-driven schema
|
||||
- [x] 5.2 Test apply instructions with tdd schema
|
||||
- [x] 5.3 Test fallback when schema has no apply block
|
||||
- [x] 5.4 Test blocked state when required artifacts missing
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-01-07
|
||||
@@ -0,0 +1,84 @@
|
||||
## Context
|
||||
|
||||
The experimental workflow (OPSX) provides a complete lifecycle for creating changes:
|
||||
- `/opsx:new` - Scaffold a new change with schema
|
||||
- `/opsx:continue` - Create next artifact
|
||||
- `/opsx:ff` - Fast-forward all artifacts
|
||||
- `/opsx:apply` - Implement tasks
|
||||
- `/opsx:sync` - Sync delta specs to main
|
||||
|
||||
The missing piece is archiving. The existing `openspec archive` command works but:
|
||||
1. Applies specs programmatically (not agent-driven)
|
||||
2. Doesn't use the artifact graph for completion checking
|
||||
3. Doesn't integrate with the OPSX workflow philosophy
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Add `/opsx:archive` skill to complete the OPSX workflow lifecycle
|
||||
- Use artifact graph for schema-aware completion checking
|
||||
- Integrate with `/opsx:sync` for agent-driven spec syncing
|
||||
- Preserve `.openspec.yaml` schema metadata in archive
|
||||
|
||||
**Non-Goals:**
|
||||
- Replacing the existing `openspec archive` CLI command
|
||||
- Changing how specs are applied in the CLI command
|
||||
- Modifying the artifact graph or schema system
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision 1: Skill-only implementation (no new CLI command)
|
||||
|
||||
The `/opsx:archive` will be a slash command/skill only, not a new CLI command.
|
||||
|
||||
**Rationale**: The existing `openspec archive` CLI command already handles the core archive functionality (moving to archive folder, date prefixing). The OPSX version just needs different pre-archive checks and optional sync prompting, which are agent behaviors better suited to a skill.
|
||||
|
||||
**Alternatives considered**:
|
||||
- Adding flags to `openspec archive` (e.g., `--experimental`) - Rejected: adds complexity to CLI, harder to maintain two code paths
|
||||
- New CLI command `openspec archive-experimental` - Rejected: unnecessary duplication, agent skills are the OPSX pattern
|
||||
|
||||
### Decision 2: Prompt for sync before archive
|
||||
|
||||
The skill will check for unsynced delta specs and prompt the user before archiving.
|
||||
|
||||
**Rationale**: The OPSX philosophy is agent-driven intelligent merging via `/opsx:sync`. Rather than programmatically applying specs like the regular archive command, we prompt the user to sync first if needed. This maintains workflow flexibility (user can decline and just archive).
|
||||
|
||||
**Flow**:
|
||||
1. Check if `specs/` directory exists in the change
|
||||
2. If yes, ask: "This change has delta specs. Would you like to sync them to main specs before archiving?"
|
||||
3. If user says yes, execute `/opsx:sync` logic
|
||||
4. Proceed with archive regardless of answer
|
||||
|
||||
### Decision 3: Use artifact graph for completion checking
|
||||
|
||||
The skill will use `openspec status --change "<name>" --json` to check artifact completion instead of just validating proposal.md and specs.
|
||||
|
||||
**Rationale**: The experimental workflow is schema-aware. Different schemas have different required artifacts. The artifact graph knows which artifacts are complete/incomplete for the current schema.
|
||||
|
||||
**Behavior**:
|
||||
- Show warning if any artifacts are not `done`
|
||||
- Don't block archive (user may have valid reasons to archive early)
|
||||
- List incomplete artifacts so user can make informed decision
|
||||
|
||||
### Decision 4: Reuse tasks.md completion check from regular archive
|
||||
|
||||
The skill will parse tasks.md and warn about incomplete tasks, same as regular archive.
|
||||
|
||||
**Rationale**: Task completion checking is valuable regardless of workflow. The logic is simple (count `- [ ]` vs `- [x]`) and doesn't need special OPSX handling.
|
||||
|
||||
### Decision 5: Move change to archive/ with date prefix
|
||||
|
||||
Same archive behavior as regular command: move to `openspec/changes/archive/YYYY-MM-DD-<name>/`.
|
||||
|
||||
**Rationale**: Consistency with existing archive convention. The `.openspec.yaml` file moves with the change, preserving schema metadata.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
**Risk**: Users confused about when to use `/opsx:archive` vs `openspec archive`
|
||||
→ **Mitigation**: Documentation should clarify: use `/opsx:archive` if you've been using the OPSX workflow, use `openspec archive` otherwise. Both produce the same archived result.
|
||||
|
||||
**Risk**: Incomplete sync if user declines and has delta specs
|
||||
→ **Mitigation**: The prompt is informational; user has full control. They may want to archive without syncing (e.g., abandoned change). Log a note in output.
|
||||
|
||||
**Trade-off**: No programmatic spec application in OPSX archive
|
||||
→ **Accepted**: This is intentional. OPSX philosophy is agent-driven merging. If user wants programmatic application, use `openspec archive` instead.
|
||||
@@ -0,0 +1,28 @@
|
||||
## Why
|
||||
|
||||
The experimental workflow (OPSX) provides a schema-driven, artifact-by-artifact approach to creating changes with `/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:apply`, and `/opsx:sync`. However, there's no corresponding archive command to finalize and archive completed changes. Users must currently fall back to the regular `openspec archive` command, which doesn't integrate with the OPSX philosophy of agent-driven spec syncing and schema-aware artifact tracking.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add `/opsx:archive` slash command for archiving changes in the experimental workflow
|
||||
- Use artifact graph to check completion status (schema-aware) instead of just validating proposal + specs
|
||||
- Prompt for `/opsx:sync` before archiving instead of programmatically applying specs
|
||||
- Preserve `.openspec.yaml` schema metadata when moving to archive
|
||||
- Integrate with existing OPSX commands for a cohesive workflow
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `opsx-archive-skill`: Slash command and skill for archiving completed changes in the experimental workflow. Checks artifact completion via artifact graph, verifies task completion, optionally syncs specs via `/opsx:sync`, and moves the change to `archive/YYYY-MM-DD-<name>/`.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
(none - this is a new skill that doesn't modify existing specs)
|
||||
|
||||
## Impact
|
||||
|
||||
- New file: `.claude/commands/opsx/archive.md`
|
||||
- New skill definition (generated via `openspec artifact-experimental-setup`)
|
||||
- No changes to existing archive command or other OPSX commands
|
||||
- Completes the OPSX command suite for full lifecycle management
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: OPSX Archive Skill
|
||||
|
||||
The system SHALL provide an `/opsx:archive` skill that archives completed changes in the experimental workflow.
|
||||
|
||||
#### Scenario: Archive a change with all artifacts complete
|
||||
|
||||
- **WHEN** agent executes `/opsx:archive` with a change name
|
||||
- **AND** all artifacts in the schema are complete
|
||||
- **AND** all tasks are complete
|
||||
- **THEN** the agent moves the change to `openspec/changes/archive/YYYY-MM-DD-<name>/`
|
||||
- **AND** displays success message with archived location
|
||||
|
||||
#### Scenario: Change selection prompt
|
||||
|
||||
- **WHEN** agent executes `/opsx:archive` without specifying a change
|
||||
- **THEN** the agent prompts user to select from available changes
|
||||
- **AND** shows only active changes (excludes archive/)
|
||||
|
||||
### Requirement: Artifact Completion Check
|
||||
|
||||
The skill SHALL check artifact completion status using the artifact graph before archiving.
|
||||
|
||||
#### Scenario: Incomplete artifacts warning
|
||||
|
||||
- **WHEN** agent checks artifact status
|
||||
- **AND** one or more artifacts have status other than `done`
|
||||
- **THEN** display warning listing incomplete artifacts
|
||||
- **AND** prompt user for confirmation to continue
|
||||
- **AND** proceed if user confirms
|
||||
|
||||
#### Scenario: All artifacts complete
|
||||
|
||||
- **WHEN** agent checks artifact status
|
||||
- **AND** all artifacts have status `done`
|
||||
- **THEN** proceed without warning
|
||||
|
||||
### Requirement: Task Completion Check
|
||||
|
||||
The skill SHALL check task completion status from tasks.md before archiving.
|
||||
|
||||
#### Scenario: Incomplete tasks found
|
||||
|
||||
- **WHEN** agent reads tasks.md
|
||||
- **AND** incomplete tasks are found (marked with `- [ ]`)
|
||||
- **THEN** display warning showing count of incomplete tasks
|
||||
- **AND** prompt user for confirmation to continue
|
||||
- **AND** proceed if user confirms
|
||||
|
||||
#### Scenario: All tasks complete
|
||||
|
||||
- **WHEN** agent reads tasks.md
|
||||
- **AND** all tasks are complete (marked with `- [x]`)
|
||||
- **THEN** proceed without task-related warning
|
||||
|
||||
#### Scenario: No tasks file
|
||||
|
||||
- **WHEN** tasks.md does not exist
|
||||
- **THEN** proceed without task-related warning
|
||||
|
||||
### Requirement: Spec Sync Prompt
|
||||
|
||||
The skill SHALL prompt to sync delta specs before archiving if specs exist.
|
||||
|
||||
#### Scenario: Delta specs exist
|
||||
|
||||
- **WHEN** agent checks for delta specs
|
||||
- **AND** `specs/` directory exists in the change with spec files
|
||||
- **THEN** prompt user: "This change has delta specs. Would you like to sync them to main specs before archiving?"
|
||||
- **AND** if user confirms, execute `/opsx:sync` logic
|
||||
- **AND** proceed with archive regardless of sync choice
|
||||
|
||||
#### Scenario: No delta specs
|
||||
|
||||
- **WHEN** agent checks for delta specs
|
||||
- **AND** no `specs/` directory or no spec files exist
|
||||
- **THEN** proceed without sync prompt
|
||||
|
||||
### Requirement: Archive Process
|
||||
|
||||
The skill SHALL move the change to the archive folder with date prefix.
|
||||
|
||||
#### Scenario: Successful archive
|
||||
|
||||
- **WHEN** archiving a change
|
||||
- **THEN** create `archive/` directory if it doesn't exist
|
||||
- **AND** generate target name as `YYYY-MM-DD-<change-name>` using current date
|
||||
- **AND** move entire change directory to archive location
|
||||
- **AND** preserve `.openspec.yaml` file in archived change
|
||||
|
||||
#### Scenario: Archive already exists
|
||||
|
||||
- **WHEN** target archive directory already exists
|
||||
- **THEN** fail with error message
|
||||
- **AND** suggest renaming existing archive or using different date
|
||||
|
||||
### Requirement: Skill Output
|
||||
|
||||
The skill SHALL provide clear feedback about the archive operation.
|
||||
|
||||
#### Scenario: Archive complete with sync
|
||||
|
||||
- **WHEN** archive completes after syncing specs
|
||||
- **THEN** display summary:
|
||||
- Specs synced (from `/opsx:sync` output)
|
||||
- Change archived to location
|
||||
- Schema that was used
|
||||
|
||||
#### Scenario: Archive complete without sync
|
||||
|
||||
- **WHEN** archive completes without syncing specs
|
||||
- **THEN** display summary:
|
||||
- Note that specs were not synced (if applicable)
|
||||
- Change archived to location
|
||||
- Schema that was used
|
||||
|
||||
#### Scenario: Archive complete with warnings
|
||||
|
||||
- **WHEN** archive completes with incomplete artifacts or tasks
|
||||
- **THEN** include note about what was incomplete
|
||||
- **AND** suggest reviewing if archive was intentional
|
||||
@@ -0,0 +1,23 @@
|
||||
## 1. Create Slash Command
|
||||
|
||||
- [x] 1.1 Create `.claude/commands/opsx/archive.md` with skill definition
|
||||
- [x] 1.2 Add YAML frontmatter (name, description, category, tags)
|
||||
- [x] 1.3 Implement change selection logic (prompt if not provided)
|
||||
- [x] 1.4 Implement artifact completion check using `openspec status --json`
|
||||
- [x] 1.5 Implement task completion check (parse tasks.md for `- [ ]`)
|
||||
- [x] 1.6 Implement spec sync prompt (check for specs/ directory, offer `/opsx:sync`)
|
||||
- [x] 1.7 Implement archive process (move to archive/YYYY-MM-DD-<name>/)
|
||||
- [x] 1.8 Add output formatting for success/warning cases
|
||||
|
||||
## 2. Regenerate Skills
|
||||
|
||||
- [x] 2.1 Run `openspec artifact-experimental-setup` to regenerate skills
|
||||
- [x] 2.2 Verify skill appears in `.claude/skills/` directory
|
||||
|
||||
## 3. Testing
|
||||
|
||||
- [x] 3.1 Test `/opsx:archive` with a complete change (all artifacts, all tasks done)
|
||||
- [x] 3.2 Test `/opsx:archive` with incomplete artifacts (verify warning shown)
|
||||
- [x] 3.3 Test `/opsx:archive` with incomplete tasks (verify warning shown)
|
||||
- [x] 3.4 Test `/opsx:archive` with delta specs (verify sync prompt shown)
|
||||
- [x] 3.5 Test `/opsx:archive` without change name (verify selection prompt)
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-01-07
|
||||
@@ -0,0 +1,94 @@
|
||||
## Context
|
||||
|
||||
OpenSpec is a TypeScript CLI tool using pnpm for dependency management. The project requires Node.js ≥20.19.0. Nix uses its own build system that needs to understand how to fetch dependencies and build the project reproducibly.
|
||||
|
||||
The Nix ecosystem has specific patterns for packaging Node.js/pnpm projects that differ from the traditional npm ecosystem.
|
||||
|
||||
## Goals
|
||||
|
||||
- Enable OpenSpec to be run directly via `nix run github:Fission-AI/OpenSpec`
|
||||
- Support all major platforms (Linux x86/ARM, macOS x86/ARM)
|
||||
- Use existing pnpm-lock.yaml for reproducible builds
|
||||
- Provide development environment for Nix users
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Replace existing npm/pnpm publishing workflow
|
||||
- Publish to nixpkgs (can be done later as separate effort)
|
||||
- Support Windows (Nix doesn't run natively on Windows)
|
||||
|
||||
## Decisions
|
||||
|
||||
### Use stdenv.mkDerivation instead of buildNpmPackage
|
||||
|
||||
**Decision**: Package OpenSpec using `stdenv.mkDerivation` with pnpm hooks.
|
||||
|
||||
**Rationale**: The zigbee2mqtt package in nixpkgs demonstrates the current best practice for pnpm projects. Using `buildNpmPackage` with pnpm requires complex configuration, while `mkDerivation` with the right hooks is more straightforward and better supported.
|
||||
|
||||
**Alternative considered**: Using `buildNpmPackage` with `npmConfigHook = pkgs.pnpmConfigHook` - this is the older pattern and causes issues with dependency fetching.
|
||||
|
||||
### Use fetchPnpmDeps with explicit pnpm version
|
||||
|
||||
**Decision**: Use `pkgs.fetchPnpmDeps` with `pnpm = pkgs.pnpm_9` and `fetcherVersion = 3`.
|
||||
|
||||
**Rationale**:
|
||||
- pnpm lockfile version 9.0 requires fetcherVersion 3
|
||||
- Explicit pnpm_9 ensures consistency between fetch and build
|
||||
- This is the documented way to handle pnpm projects in nixpkgs
|
||||
|
||||
### Multi-platform support without flake-utils
|
||||
|
||||
**Decision**: Implement multi-platform support using plain Nix with `nixpkgs.lib.genAttrs`.
|
||||
|
||||
**Rationale**: Per user request, avoid extra dependencies. The `genAttrs` pattern is simple and well-understood in the Nix community.
|
||||
|
||||
### Node.js 20 instead of latest
|
||||
|
||||
**Decision**: Pin to nodejs_20 to match package.json engines requirement.
|
||||
|
||||
**Rationale**: Ensures consistency with development environment and npm package requirements. Avoids potential compatibility issues with newer Node versions.
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
### Dependency Hash Management
|
||||
|
||||
The `pnpmDeps.hash` field must be updated whenever dependencies change. The workflow:
|
||||
1. Set hash to fake value (all zeros)
|
||||
2. Run `nix build`
|
||||
3. Nix fails with actual hash
|
||||
4. Update flake.nix with correct hash
|
||||
|
||||
This is standard Nix workflow for fixed-output derivations.
|
||||
|
||||
### Build Inputs
|
||||
|
||||
Required nativeBuildInputs:
|
||||
- `nodejs_20` - runtime
|
||||
- `npmHooks.npmInstallHook` - handles installation phase
|
||||
- `pnpmConfigHook` - configures pnpm environment
|
||||
- `pnpm_9` - pnpm executable
|
||||
|
||||
The `dontNpmPrune = true` is important to keep all dependencies after build.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
**[Risk]** Hash needs updating when dependencies change → **Mitigation**: Document this clearly; error message from Nix provides correct hash
|
||||
|
||||
**[Risk]** Nix builds might lag behind npm releases → **Mitigation**: This is fine; Nix users can still use npm if they need bleeding edge
|
||||
|
||||
**[Trade-off]** Additional maintenance burden for hash updates → **Benefit**: Better experience for Nix ecosystem users
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Add flake.nix to repository
|
||||
2. Test builds on multiple platforms (can use GitHub Actions with Nix)
|
||||
3. Update README with Nix installation instructions
|
||||
4. Optionally add to CI pipeline to catch hash mismatches early
|
||||
|
||||
No breaking changes - this is purely additive.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Should we add automatic hash updating to CI? (Could use nix-update-script)
|
||||
- Should we submit to nixpkgs after validation? (Separate decision)
|
||||
- Do we want to support older Node versions in flake? (Probably no - stick to package.json requirement)
|
||||
@@ -0,0 +1,25 @@
|
||||
## Why
|
||||
|
||||
OpenSpec users on NixOS or using the Nix package manager cannot easily install or run OpenSpec without going through npm. Adding a Nix flake makes OpenSpec a first-class citizen in the Nix ecosystem, enabling users to run `nix run github:Fission-AI/OpenSpec -- init` or include OpenSpec in their development environments declaratively.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add `flake.nix` to repository root with multi-platform support (x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin)
|
||||
- Package uses pnpm for dependency management (matching existing development workflow)
|
||||
- Support both direct execution via `nix run` and installation via `nix profile install`
|
||||
- Provide dev shell for contributors using Nix
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `nix-flake-support`: Nix flake configuration for building and running OpenSpec
|
||||
|
||||
### Modified Capabilities
|
||||
- None
|
||||
|
||||
## Impact
|
||||
|
||||
- **New files**: `flake.nix` in repository root
|
||||
- **Documentation**: Should add installation instructions for Nix users
|
||||
- **CI/CD**: Could add flake checking to CI pipeline (optional)
|
||||
- **Maintenance**: Requires updating pnpmDeps hash when dependencies change
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Multi-platform Nix flake
|
||||
The system SHALL provide a Nix flake that builds OpenSpec for multiple platforms.
|
||||
|
||||
#### Scenario: Build on Linux x86_64
|
||||
- **WHEN** user runs `nix build` on x86_64-linux system
|
||||
- **THEN** system builds OpenSpec package successfully
|
||||
- **AND** package includes the `openspec` binary
|
||||
|
||||
#### Scenario: Build on macOS ARM
|
||||
- **WHEN** user runs `nix build` on aarch64-darwin system
|
||||
- **THEN** system builds OpenSpec package successfully
|
||||
- **AND** package includes the `openspec` binary
|
||||
|
||||
#### Scenario: Build on Linux ARM
|
||||
- **WHEN** user runs `nix build` on aarch64-linux system
|
||||
- **THEN** system builds OpenSpec package successfully
|
||||
|
||||
#### Scenario: Build on macOS x86_64
|
||||
- **WHEN** user runs `nix build` on x86_64-darwin system
|
||||
- **THEN** system builds OpenSpec package successfully
|
||||
|
||||
### Requirement: Direct execution via nix run
|
||||
The system SHALL allow users to run OpenSpec directly from GitHub without installing.
|
||||
|
||||
#### Scenario: Run init command from GitHub
|
||||
- **WHEN** user runs `nix run github:Fission-AI/OpenSpec -- init`
|
||||
- **THEN** system downloads and builds OpenSpec
|
||||
- **AND** executes `openspec init` command
|
||||
|
||||
#### Scenario: Run any OpenSpec command
|
||||
- **WHEN** user runs `nix run github:Fission-AI/OpenSpec -- <command> <args>`
|
||||
- **THEN** system executes `openspec <command> <args>`
|
||||
|
||||
### Requirement: pnpm dependency management
|
||||
The system SHALL use pnpm for building OpenSpec in the Nix flake.
|
||||
|
||||
#### Scenario: Fetch dependencies with pnpm
|
||||
- **WHEN** Nix builds the package
|
||||
- **THEN** system uses `fetchPnpmDeps` to download dependencies
|
||||
- **AND** uses pnpm-lock.yaml for reproducible builds
|
||||
- **AND** uses fetcherVersion 3 for lockfile version 9.0
|
||||
|
||||
#### Scenario: Build with pnpm
|
||||
- **WHEN** Nix runs the build phase
|
||||
- **THEN** system executes `pnpm run build`
|
||||
- **AND** produces dist directory with compiled TypeScript
|
||||
|
||||
### Requirement: Node.js version compatibility
|
||||
The system SHALL use Node.js 20 as specified in package.json engines field.
|
||||
|
||||
#### Scenario: Build with correct Node version
|
||||
- **WHEN** Nix builds OpenSpec
|
||||
- **THEN** system uses nodejs_20 from nixpkgs
|
||||
- **AND** build succeeds without version compatibility errors
|
||||
|
||||
### Requirement: Development shell
|
||||
The system SHALL provide a Nix development shell for contributors.
|
||||
|
||||
#### Scenario: Enter dev shell
|
||||
- **WHEN** user runs `nix develop` in OpenSpec repository
|
||||
- **THEN** system provides shell with nodejs_20 and pnpm_9
|
||||
- **AND** displays welcome message with versions
|
||||
- **AND** provides instructions to run `pnpm install`
|
||||
|
||||
### Requirement: Proper binary installation
|
||||
The system SHALL install the openspec binary correctly.
|
||||
|
||||
#### Scenario: Binary in PATH
|
||||
- **WHEN** package is built or installed
|
||||
- **THEN** `openspec` binary is available in `$out/bin/openspec`
|
||||
- **AND** binary is executable
|
||||
- **AND** binary can be invoked without full path when installed
|
||||
|
||||
#### Scenario: Binary executes correctly
|
||||
- **WHEN** user runs the installed `openspec` command
|
||||
- **THEN** system executes the CLI entry point
|
||||
- **AND** all subcommands work correctly
|
||||
@@ -0,0 +1,65 @@
|
||||
## 1. Create Flake Structure
|
||||
|
||||
- [x] 1.1 Create flake.nix in repository root
|
||||
- [x] 1.2 Define inputs (nixpkgs only, no flake-utils)
|
||||
- [x] 1.3 Set up supportedSystems list (4 platforms)
|
||||
- [x] 1.4 Create forAllSystems helper function
|
||||
|
||||
## 2. Configure Package Build
|
||||
|
||||
- [x] 2.1 Set up stdenv.mkDerivation with finalAttrs pattern
|
||||
- [x] 2.2 Configure pnpmDeps with fetchPnpmDeps
|
||||
- [x] 2.3 Set pnpm = pnpm_9 and fetcherVersion = 3
|
||||
- [x] 2.4 Add placeholder hash (all zeros)
|
||||
- [x] 2.5 Configure nativeBuildInputs (nodejs_20, hooks, pnpm_9)
|
||||
- [x] 2.6 Set dontNpmPrune = true
|
||||
|
||||
## 3. Define Build Phase
|
||||
|
||||
- [x] 3.1 Add buildPhase with runHook preBuild
|
||||
- [x] 3.2 Add pnpm run build command
|
||||
- [x] 3.3 Add runHook postBuild
|
||||
|
||||
## 4. Configure Installation
|
||||
|
||||
- [x] 4.1 Let npmInstallHook handle installation automatically
|
||||
- [x] 4.2 Verify binary ends up in $out/bin/openspec
|
||||
|
||||
## 5. Add Metadata
|
||||
|
||||
- [x] 5.1 Set meta.description
|
||||
- [x] 5.2 Set meta.homepage
|
||||
- [x] 5.3 Set meta.license (MIT)
|
||||
- [x] 5.4 Set meta.mainProgram = "openspec"
|
||||
|
||||
## 6. Configure App Entry Point
|
||||
|
||||
- [x] 6.1 Add apps output with forAllSystems
|
||||
- [x] 6.2 Set default app to openspec binary
|
||||
- [x] 6.3 Test that nix run works
|
||||
|
||||
## 7. Add Development Shell
|
||||
|
||||
- [x] 7.1 Add devShells output with forAllSystems
|
||||
- [x] 7.2 Include nodejs_20 and pnpm_9 in buildInputs
|
||||
- [x] 7.3 Add shellHook with welcome message and instructions
|
||||
|
||||
## 8. Get Correct Dependency Hash
|
||||
|
||||
- [x] 8.1 Run nix build to trigger hash mismatch
|
||||
- [x] 8.2 Copy correct hash from error message
|
||||
- [x] 8.3 Update pnpmDeps.hash in flake.nix
|
||||
- [x] 8.4 Verify build succeeds
|
||||
|
||||
## 9. Testing
|
||||
|
||||
- [x] 9.1 Test `nix build` on x86_64-linux
|
||||
- [x] 9.2 Test `nix run . -- --version` works
|
||||
- [x] 9.3 Test `nix develop` provides correct environment
|
||||
- [ ] 9.4 Test on macOS if available
|
||||
- [ ] 9.5 Test `nix run github:Fission-AI/OpenSpec -- init` after merge to main
|
||||
|
||||
## 10. Documentation
|
||||
|
||||
- [x] 10.1 Add Nix installation section to README
|
||||
- [x] 10.2 Include example commands for common Nix workflows in README
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-01-09
|
||||
@@ -0,0 +1,117 @@
|
||||
## Context
|
||||
|
||||
The Nix flake added in the previous change requires manual maintenance when:
|
||||
1. Package version changes (must update flake.nix version field)
|
||||
2. Dependencies change (must update pnpmDeps hash)
|
||||
|
||||
Currently this requires maintainers to:
|
||||
- Manually edit flake.nix version
|
||||
- Set placeholder hash
|
||||
- Run nix build to get error
|
||||
- Copy hash from error message
|
||||
- Update flake.nix again
|
||||
- Verify build works
|
||||
|
||||
This is tedious and error-prone, especially for maintainers unfamiliar with Nix.
|
||||
|
||||
## Goals
|
||||
|
||||
- Automate version and hash updates for flake.nix
|
||||
- Make script idempotent and safe to run multiple times
|
||||
- Provide clear feedback during execution
|
||||
- Integrate easily into release workflow
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Automatically commit changes (maintainer decides when to commit)
|
||||
- Support non-pnpm package managers
|
||||
- Handle complex Nix configurations beyond OpenSpec's use case
|
||||
|
||||
## Decisions
|
||||
|
||||
### Use Bash instead of Node.js script
|
||||
|
||||
**Decision**: Implement as bash script rather than Node.js.
|
||||
|
||||
**Rationale**:
|
||||
- Needs to call Nix commands which are bash-native
|
||||
- Parsing Nix output is simpler in bash with grep/sed
|
||||
- Maintainers updating flake.nix likely have Nix installed (bash environment)
|
||||
- Node.js would add unnecessary complexity for shell operations
|
||||
|
||||
**Alternative considered**: Node.js script with child_process - adds dependency on extra npm packages for shell operations, less natural for Nix tooling.
|
||||
|
||||
### Extract hash from build error output
|
||||
|
||||
**Decision**: Trigger intentional build failure with placeholder hash to get correct hash.
|
||||
|
||||
**Rationale**: This is the standard Nix workflow for updating fixed-output derivations. No API exists to compute the hash without building.
|
||||
|
||||
**Alternative considered**: Pre-compute hash from pnpm-lock.yaml - would require understanding Nix's hash algorithm and pnpm's lockfile structure, fragile and non-standard.
|
||||
|
||||
### Use sed for in-place file editing
|
||||
|
||||
**Decision**: Use `sed -i` for updating flake.nix in place.
|
||||
|
||||
**Rationale**: Simple, available on all Unix-like systems, handles the specific replacement patterns needed.
|
||||
|
||||
**Alternative considered**:
|
||||
- Using Node.js to parse/modify: Overkill for simple string replacement
|
||||
- Manual `sed` without `-i`: Requires temp files, more complex
|
||||
|
||||
### Verify build after hash update
|
||||
|
||||
**Decision**: Always run verification build after updating hash.
|
||||
|
||||
**Rationale**: Catches errors immediately, gives maintainer confidence the update worked.
|
||||
|
||||
**Trade-off**: Takes extra time (~30s) but prevents broken flake.nix commits.
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
### Path Resolution
|
||||
|
||||
Script calculates paths relative to its own location:
|
||||
```bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
```
|
||||
|
||||
This allows running from any working directory.
|
||||
|
||||
### Error Handling
|
||||
|
||||
Uses `set -euo pipefail` for strict error handling:
|
||||
- `-e`: Exit on any command failure
|
||||
- `-u`: Exit on undefined variable access
|
||||
- `-o pipefail`: Catch failures in pipes
|
||||
|
||||
### Hash Extraction Pattern
|
||||
|
||||
Uses grep with Perl regex to extract hash:
|
||||
```bash
|
||||
grep -oP 'got:\s+\Ksha256-[A-Za-z0-9+/=]+'
|
||||
```
|
||||
|
||||
This reliably extracts the hash regardless of surrounding text.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
**[Risk]** Script assumes standard Nix error message format → **Mitigation**: If extraction fails, script exits with error and shows full output
|
||||
|
||||
**[Risk]** Build might fail for reasons other than hash mismatch → **Mitigation**: Script checks for hash in output before proceeding
|
||||
|
||||
**[Trade-off]** Requires Nix installed to run → **Benefit**: Only maintainers updating flake need to run this, and they have Nix
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Add script to scripts directory
|
||||
2. Document in scripts/README.md
|
||||
3. Use in next version bump to verify workflow
|
||||
4. Update CONTRIBUTING.md if needed to mention script
|
||||
|
||||
No breaking changes - purely additive tooling.
|
||||
|
||||
## Open Questions
|
||||
|
||||
None - straightforward automation script.
|
||||
@@ -0,0 +1,23 @@
|
||||
## Why
|
||||
|
||||
Maintaining the Nix flake requires manual updates to version and dependency hash when releasing new versions or updating dependencies. This is error-prone and requires maintainers to understand Nix internals. Automating this process ensures consistency and reduces friction for releases.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add `scripts/update-flake.sh` to automatically update flake.nix version and dependency hash
|
||||
- Add `scripts/README.md` documenting all maintenance scripts
|
||||
- Script extracts version from package.json and determines correct pnpm dependency hash automatically
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `flake-update-script`: Automation script for maintaining flake.nix
|
||||
|
||||
### Modified Capabilities
|
||||
- None
|
||||
|
||||
## Impact
|
||||
|
||||
- **New files**: `scripts/update-flake.sh`, `scripts/README.md`
|
||||
- **Maintainer workflow**: Version bumps now include running `./scripts/update-flake.sh`
|
||||
- **Dependencies**: Script requires Node.js (already a dependency) and Nix (for maintainers using Nix)
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Automatic Version Update
|
||||
The script SHALL automatically update the version in flake.nix to match package.json.
|
||||
|
||||
#### Scenario: Version extraction from package.json
|
||||
- **WHEN** script runs
|
||||
- **THEN** version is read from package.json using Node.js
|
||||
- **AND** version field in flake.nix is updated to match
|
||||
|
||||
#### Scenario: Version already up-to-date
|
||||
- **WHEN** script runs and flake.nix version already matches package.json
|
||||
- **THEN** script reports version is up-to-date
|
||||
- **AND** continues to hash update
|
||||
|
||||
### Requirement: Automatic Hash Determination
|
||||
The script SHALL automatically determine and update the correct pnpm dependency hash.
|
||||
|
||||
#### Scenario: Trigger build to get hash
|
||||
- **WHEN** script needs to determine correct hash
|
||||
- **THEN** script sets placeholder hash in flake.nix
|
||||
- **AND** runs nix build which fails with correct hash
|
||||
- **AND** extracts correct hash from build error output
|
||||
|
||||
#### Scenario: Hash extraction from build output
|
||||
- **WHEN** nix build fails with hash mismatch
|
||||
- **THEN** script parses "got: sha256-..." from error output
|
||||
- **AND** updates flake.nix with correct hash
|
||||
|
||||
#### Scenario: Hash update failure
|
||||
- **WHEN** script cannot extract hash from build output
|
||||
- **THEN** script exits with error
|
||||
- **AND** displays build output for debugging
|
||||
|
||||
### Requirement: Build Verification
|
||||
The script SHALL verify that flake.nix builds successfully after updates.
|
||||
|
||||
#### Scenario: Successful verification
|
||||
- **WHEN** hash has been updated
|
||||
- **THEN** script runs nix build to verify
|
||||
- **AND** reports success if build completes
|
||||
|
||||
#### Scenario: Dirty git tree warning
|
||||
- **WHEN** build succeeds but git tree is dirty
|
||||
- **THEN** script reports warning about dirty tree
|
||||
- **AND** still indicates build success
|
||||
|
||||
### Requirement: User Feedback
|
||||
The script SHALL provide clear progress information and next steps.
|
||||
|
||||
#### Scenario: Progress reporting
|
||||
- **WHEN** script runs
|
||||
- **THEN** each step is reported with descriptive message
|
||||
- **AND** detected version and hash are displayed
|
||||
|
||||
#### Scenario: Success summary
|
||||
- **WHEN** script completes successfully
|
||||
- **THEN** summary shows updated version and hash
|
||||
- **AND** next steps are displayed (test, commit, etc.)
|
||||
|
||||
### Requirement: Script Safety
|
||||
The script SHALL fail fast on errors and use safe defaults.
|
||||
|
||||
#### Scenario: Bash error handling
|
||||
- **WHEN** script encounters an error
|
||||
- **THEN** script exits immediately (set -e)
|
||||
- **AND** undefined variables cause exit (set -u)
|
||||
- **AND** pipe failures are caught (set -o pipefail)
|
||||
|
||||
#### Scenario: File path resolution
|
||||
- **WHEN** script determines file locations
|
||||
- **THEN** paths are calculated relative to script location
|
||||
- **AND** script works regardless of working directory
|
||||
|
||||
### Requirement: Documentation
|
||||
The system SHALL provide documentation for the update script.
|
||||
|
||||
#### Scenario: Script usage documentation
|
||||
- **WHEN** maintainer needs to use update script
|
||||
- **THEN** scripts/README.md explains when and how to use it
|
||||
- **AND** example workflow is provided
|
||||
|
||||
#### Scenario: Script listing
|
||||
- **WHEN** maintainer views scripts/README.md
|
||||
- **THEN** all maintenance scripts are documented
|
||||
- **AND** purpose of each script is clear
|
||||
@@ -0,0 +1,55 @@
|
||||
## 1. Create Update Script
|
||||
|
||||
- [x] 1.1 Create scripts/update-flake.sh file
|
||||
- [x] 1.2 Add shebang and error handling (set -euo pipefail)
|
||||
- [x] 1.3 Add path resolution for project root and files
|
||||
- [x] 1.4 Make script executable (chmod +x)
|
||||
|
||||
## 2. Implement Version Update Logic
|
||||
|
||||
- [x] 2.1 Extract version from package.json using Node.js
|
||||
- [x] 2.2 Use sed to update version in flake.nix
|
||||
- [x] 2.3 Report if version already up-to-date
|
||||
- [x] 2.4 Display detected version to user
|
||||
|
||||
## 3. Implement Hash Update Logic
|
||||
|
||||
- [x] 3.1 Set placeholder hash in flake.nix
|
||||
- [x] 3.2 Run nix build and capture output (allow failure)
|
||||
- [x] 3.3 Extract correct hash from build error using grep
|
||||
- [x] 3.4 Handle case where hash extraction fails
|
||||
- [x] 3.5 Update flake.nix with correct hash
|
||||
- [x] 3.6 Display detected hash to user
|
||||
|
||||
## 4. Add Build Verification
|
||||
|
||||
- [x] 4.1 Run nix build after hash update
|
||||
- [x] 4.2 Check for dirty git tree warning
|
||||
- [x] 4.3 Report success or failure clearly
|
||||
|
||||
## 5. Add User Feedback
|
||||
|
||||
- [x] 5.1 Add progress messages for each step
|
||||
- [x] 5.2 Add success summary with version and hash
|
||||
- [x] 5.3 Add next steps instructions (test, commit)
|
||||
- [x] 5.4 Add error messages with context
|
||||
|
||||
## 6. Create Documentation
|
||||
|
||||
- [x] 6.1 Create scripts/README.md
|
||||
- [x] 6.2 Document update-flake.sh purpose and usage
|
||||
- [x] 6.3 Add example workflow
|
||||
- [x] 6.4 Document other existing scripts
|
||||
|
||||
## 7. Testing
|
||||
|
||||
- [x] 7.1 Test script runs successfully
|
||||
- [x] 7.2 Verify version is extracted correctly
|
||||
- [x] 7.3 Verify hash is updated correctly
|
||||
- [x] 7.4 Verify build succeeds after update
|
||||
- [x] 7.5 Test idempotency (running twice works)
|
||||
|
||||
## 8. Integration
|
||||
|
||||
- [ ] 8.1 Add note to release process documentation
|
||||
- [ ] 8.2 Use in next actual version bump to validate workflow
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-01-10
|
||||
@@ -0,0 +1,175 @@
|
||||
## Context
|
||||
|
||||
OpenSpec needs usage analytics to understand adoption and inform product decisions. PostHog provides a privacy-conscious analytics platform suitable for open source projects.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Track daily/weekly/monthly active usage
|
||||
- Understand command usage patterns
|
||||
- Keep implementation minimal and privacy-respecting
|
||||
- Enable opt-out with minimal friction
|
||||
|
||||
**Non-Goals:**
|
||||
- Detailed error tracking or diagnostics
|
||||
- User identification or profiling
|
||||
- Complex event hierarchies
|
||||
- Full CLI command for telemetry management (env var sufficient for now)
|
||||
|
||||
## Decisions
|
||||
|
||||
### Opt-Out Model
|
||||
|
||||
**Decision:** Telemetry enabled by default, opt-out via environment variable.
|
||||
|
||||
```bash
|
||||
OPENSPEC_TELEMETRY=0 # Disable telemetry
|
||||
DO_NOT_TRACK=1 # Industry standard, also respected
|
||||
```
|
||||
|
||||
Auto-disabled when `CI=true` is detected.
|
||||
|
||||
**Rationale:**
|
||||
- Opt-in typically yields ~3% participation—not enough for meaningful data
|
||||
- Understanding usage patterns requires statistically significant sample sizes
|
||||
- Environment variable opt-out is simple and immediate
|
||||
- Respecting `DO_NOT_TRACK` follows industry convention
|
||||
|
||||
**Alternatives considered:**
|
||||
- Opt-in only - Insufficient data for product decisions
|
||||
- Config file setting - More complex, env var sufficient for MVP
|
||||
- Full `openspec telemetry` command - Can add later if users request
|
||||
|
||||
### Event Design
|
||||
|
||||
**Decision:** Single event type with minimal properties.
|
||||
|
||||
```typescript
|
||||
{
|
||||
event: 'command_executed',
|
||||
properties: {
|
||||
command: 'init', // Command name only
|
||||
version: '1.2.3' // OpenSpec version
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- Answers the core questions: how much usage, which commands are popular
|
||||
- PostHog derives DAU/WAU/MAU from anonymous user counts over time
|
||||
- No arguments, paths, or content—clean privacy story
|
||||
- Easy to explain in disclosure notice
|
||||
|
||||
**Not tracked:**
|
||||
- Command arguments
|
||||
- File paths or contents
|
||||
- Error messages or stack traces
|
||||
- Project names or spec content
|
||||
- IP addresses (`$ip: null` explicitly set)
|
||||
|
||||
### Anonymous ID
|
||||
|
||||
**Decision:** Random UUID, lazily generated on first telemetry send, stored in global config.
|
||||
|
||||
```typescript
|
||||
// ~/.config/openspec/config.json
|
||||
{
|
||||
"telemetry": {
|
||||
"anonymousId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- Random UUID has no relation to the person—can't be reversed
|
||||
- Stored in config so same user = same ID across sessions (needed for DAU/WAU/MAU)
|
||||
- Lazy generation means no ID created if user opts out before first command
|
||||
- User can delete config to reset identity
|
||||
|
||||
**Alternatives considered:**
|
||||
- Machine-derived hash (hostname, MAC) - Feels invasive, fingerprint-like
|
||||
- Per-session UUID - Breaks user counting metrics entirely
|
||||
|
||||
### SDK Configuration
|
||||
|
||||
**Decision:** PostHog Node SDK with immediate flush, shutdown on exit.
|
||||
|
||||
```typescript
|
||||
const posthog = new PostHog(API_KEY, {
|
||||
flushAt: 1, // Send immediately, don't batch
|
||||
flushInterval: 0 // No timer-based flushing
|
||||
});
|
||||
|
||||
// Before CLI exits
|
||||
await posthog.shutdown();
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- CLI processes are short-lived; batching would lose events
|
||||
- `flushAt: 1` ensures each event sends immediately
|
||||
- `shutdown()` guarantees flush before process exit
|
||||
- Adds ~100-300ms to exit—negligible for typical CLI workflows
|
||||
|
||||
**Error handling:**
|
||||
- Network failures silently ignored (telemetry shouldn't break CLI)
|
||||
- `shutdown()` wrapped in try/catch
|
||||
|
||||
### Hook Location
|
||||
|
||||
**Decision:** Commander.js `preAction` and `postAction` hooks.
|
||||
|
||||
```typescript
|
||||
program
|
||||
.hook('preAction', (thisCommand) => {
|
||||
maybeShowTelemetryNotice();
|
||||
trackCommand(thisCommand.name(), VERSION);
|
||||
})
|
||||
.hook('postAction', async () => {
|
||||
await shutdown();
|
||||
});
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- Centralized—one place for all telemetry logic
|
||||
- Automatic—new commands get tracked without code changes
|
||||
- Clean separation—command handlers don't know about telemetry
|
||||
|
||||
**Subcommand handling:**
|
||||
- Track full command path for nested commands (e.g., `change:apply`)
|
||||
|
||||
### First-Run Notice
|
||||
|
||||
**Decision:** One-liner on first command ever, stored "seen" flag in config.
|
||||
|
||||
```
|
||||
Note: OpenSpec collects anonymous usage stats. Opt out: OPENSPEC_TELEMETRY=0
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- First command (not just `init`) ensures notice is always seen
|
||||
- Non-blocking—no prompt, just informational
|
||||
- One-liner is visible but not intrusive
|
||||
- Storing "seen" in config prevents repeated display
|
||||
|
||||
**Config after first run:**
|
||||
```json
|
||||
{
|
||||
"telemetry": {
|
||||
"anonymousId": "...",
|
||||
"noticeSeen": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| Users prefer opt-in | Clear disclosure, trivial opt-out, transparent about what's collected |
|
||||
| GDPR concerns | No personal data, no IP, user can delete config |
|
||||
| Slows CLI exit by ~200ms | Negligible for most workflows; can optimize if needed |
|
||||
| PostHog outage affects CLI | Fire-and-forget with timeout; failures are silent |
|
||||
|
||||
## Open Questions
|
||||
|
||||
None—design is intentionally minimal. Future enhancements (dedicated command, workflow tracking) can be added based on user feedback.
|
||||
@@ -0,0 +1,37 @@
|
||||
## Why
|
||||
|
||||
OpenSpec currently has no visibility into how the tool is being used. Without analytics, we cannot:
|
||||
- Understand which commands and features are most valuable to users
|
||||
- Measure adoption and usage patterns
|
||||
- Make data-driven decisions about product development
|
||||
|
||||
Adding PostHog analytics enables product insights while respecting user privacy through transparent, opt-out telemetry.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add PostHog Node.js SDK as a dependency
|
||||
- Implement telemetry system with environment variable opt-out
|
||||
- Track command usage (command name and version only)
|
||||
- Show first-run notice informing users about telemetry
|
||||
- Store anonymous ID in global config (`~/.config/openspec/config.json`)
|
||||
- Respect `DO_NOT_TRACK` and `OPENSPEC_TELEMETRY=0` environment variables
|
||||
- Auto-disable in CI environments
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `telemetry`: Anonymous usage analytics using PostHog. Covers command tracking, opt-out controls, and first-run disclosure notice.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `global-config`: Add telemetry state storage (anonymous ID, notice seen flag)
|
||||
|
||||
## Impact
|
||||
|
||||
- **Dependencies**: Add `posthog-node` package
|
||||
- **Privacy**: Opt-out via env var, no personal data collected, clear disclosure
|
||||
- **Configuration**: New global config fields for telemetry state
|
||||
- **Network**: Async event sending with flush on exit (~100-300ms added)
|
||||
- **CI/CD**: Telemetry auto-disabled when `CI=true`
|
||||
- **Documentation**: Update README with telemetry disclosure
|
||||
@@ -0,0 +1,21 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Global configuration storage
|
||||
The system SHALL store global configuration in `~/.config/openspec/config.json`, including telemetry state with `anonymousId` and `noticeSeen` fields.
|
||||
|
||||
#### Scenario: Initial config creation
|
||||
- **WHEN** no global config file exists
|
||||
- **AND** the first telemetry event is about to be sent
|
||||
- **THEN** the system creates `~/.config/openspec/config.json` with telemetry configuration
|
||||
|
||||
#### Scenario: Telemetry config structure
|
||||
- **WHEN** reading or writing telemetry configuration
|
||||
- **THEN** the config contains a `telemetry` object with `anonymousId` (string UUID) and `noticeSeen` (boolean) fields
|
||||
|
||||
#### Scenario: Config file format
|
||||
- **WHEN** storing configuration
|
||||
- **THEN** the system writes valid JSON that can be read and modified by users
|
||||
|
||||
#### Scenario: Existing config preservation
|
||||
- **WHEN** adding telemetry fields to an existing config file
|
||||
- **THEN** the system preserves all existing configuration fields
|
||||
@@ -0,0 +1,116 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Command execution tracking
|
||||
The system SHALL send a `command_executed` event to PostHog when any CLI command executes, including only the command name and OpenSpec version as properties.
|
||||
|
||||
#### Scenario: Standard command execution
|
||||
- **WHEN** a user runs any openspec command
|
||||
- **THEN** the system sends a `command_executed` event with `command` and `version` properties
|
||||
|
||||
#### Scenario: Subcommand execution
|
||||
- **WHEN** a user runs a nested command like `openspec change apply`
|
||||
- **THEN** the system sends a `command_executed` event with the full command path (e.g., `change:apply`)
|
||||
|
||||
### Requirement: Privacy-preserving event design
|
||||
The system SHALL NOT include command arguments, file paths, project names, spec content, error messages, or IP addresses in telemetry events.
|
||||
|
||||
#### Scenario: Command with arguments
|
||||
- **WHEN** a user runs `openspec init my-project --force`
|
||||
- **THEN** the telemetry event contains only `command: "init"` and `version: "<version>"` without arguments
|
||||
|
||||
#### Scenario: IP address exclusion
|
||||
- **WHEN** the system sends a telemetry event
|
||||
- **THEN** the event explicitly sets `$ip: null` to prevent IP tracking
|
||||
|
||||
### Requirement: Environment variable opt-out
|
||||
The system SHALL disable telemetry when `OPENSPEC_TELEMETRY=0` or `DO_NOT_TRACK=1` environment variables are set.
|
||||
|
||||
#### Scenario: OPENSPEC_TELEMETRY opt-out
|
||||
- **WHEN** `OPENSPEC_TELEMETRY=0` is set in the environment
|
||||
- **THEN** the system sends no telemetry events
|
||||
|
||||
#### Scenario: DO_NOT_TRACK opt-out
|
||||
- **WHEN** `DO_NOT_TRACK=1` is set in the environment
|
||||
- **THEN** the system sends no telemetry events
|
||||
|
||||
#### Scenario: Environment variable takes precedence
|
||||
- **WHEN** the user has previously used the CLI (config exists)
|
||||
- **AND** the user sets `OPENSPEC_TELEMETRY=0`
|
||||
- **THEN** telemetry is disabled regardless of config state
|
||||
|
||||
### Requirement: CI environment auto-disable
|
||||
The system SHALL automatically disable telemetry when `CI=true` environment variable is detected.
|
||||
|
||||
#### Scenario: CI environment detection
|
||||
- **WHEN** `CI=true` is set in the environment
|
||||
- **THEN** the system sends no telemetry events
|
||||
|
||||
#### Scenario: CI with explicit enable
|
||||
- **WHEN** `CI=true` is set
|
||||
- **AND** `OPENSPEC_TELEMETRY=1` is explicitly set
|
||||
- **THEN** telemetry remains disabled (CI takes precedence for privacy)
|
||||
|
||||
### Requirement: First-run telemetry notice
|
||||
The system SHALL display a one-line telemetry disclosure notice on the first command execution, before any telemetry is sent.
|
||||
|
||||
#### Scenario: First command execution
|
||||
- **WHEN** a user runs their first openspec command
|
||||
- **AND** telemetry is enabled
|
||||
- **THEN** the system displays: "Note: OpenSpec collects anonymous usage stats. Opt out: OPENSPEC_TELEMETRY=0"
|
||||
|
||||
#### Scenario: Subsequent command execution
|
||||
- **WHEN** a user has already seen the notice (noticeSeen: true in config)
|
||||
- **THEN** the system does not display the notice
|
||||
|
||||
#### Scenario: Notice before telemetry
|
||||
- **WHEN** displaying the first-run notice
|
||||
- **THEN** the notice appears before any telemetry event is sent
|
||||
|
||||
### Requirement: Anonymous user identification
|
||||
The system SHALL generate a random UUID as an anonymous identifier on first telemetry send, stored in global config.
|
||||
|
||||
#### Scenario: First telemetry event
|
||||
- **WHEN** the first telemetry event is sent
|
||||
- **AND** no anonymousId exists in config
|
||||
- **THEN** the system generates a random UUID v4 and stores it in config
|
||||
|
||||
#### Scenario: Persistent identity
|
||||
- **WHEN** a user runs multiple commands across sessions
|
||||
- **THEN** the same anonymousId is used for all events
|
||||
|
||||
#### Scenario: Lazy generation with opt-out
|
||||
- **WHEN** a user opts out before running any command
|
||||
- **THEN** no anonymousId is ever generated or stored
|
||||
|
||||
### Requirement: Immediate event sending
|
||||
The system SHALL send telemetry events immediately without batching, using `flushAt: 1` and `flushInterval: 0` configuration.
|
||||
|
||||
#### Scenario: Event transmission timing
|
||||
- **WHEN** a command executes
|
||||
- **THEN** the telemetry event is sent immediately, not queued for batch transmission
|
||||
|
||||
### Requirement: Graceful shutdown
|
||||
The system SHALL call `posthog.shutdown()` before CLI exit to ensure pending events are flushed.
|
||||
|
||||
#### Scenario: Normal exit
|
||||
- **WHEN** a command completes successfully
|
||||
- **THEN** the system awaits `shutdown()` before exiting
|
||||
|
||||
#### Scenario: Error exit
|
||||
- **WHEN** a command fails with an error
|
||||
- **THEN** the system still awaits `shutdown()` before exiting
|
||||
|
||||
### Requirement: Silent failure handling
|
||||
The system SHALL silently ignore telemetry failures without affecting CLI functionality.
|
||||
|
||||
#### Scenario: Network failure
|
||||
- **WHEN** the telemetry request fails due to network error
|
||||
- **THEN** the CLI command completes normally without error message
|
||||
|
||||
#### Scenario: PostHog outage
|
||||
- **WHEN** PostHog service is unavailable
|
||||
- **THEN** the CLI command completes normally without error message
|
||||
|
||||
#### Scenario: Shutdown failure
|
||||
- **WHEN** `shutdown()` fails or times out
|
||||
- **THEN** the CLI exits normally without error message
|
||||
@@ -0,0 +1,47 @@
|
||||
## 1. Setup
|
||||
|
||||
- [x] 1.1 Add `posthog-node` package as a dependency
|
||||
- [x] 1.2 Create `src/telemetry/` module directory
|
||||
- [x] 1.3 Add PostHog API key configuration (environment variable or embedded)
|
||||
|
||||
## 2. Global Config
|
||||
|
||||
- [x] 2.1 Create or extend global config module for `~/.config/openspec/config.json`
|
||||
- [x] 2.2 Implement read/write functions that preserve existing config fields
|
||||
- [x] 2.3 Define telemetry config structure (`anonymousId`, `noticeSeen`)
|
||||
|
||||
## 3. Core Telemetry Module
|
||||
|
||||
- [x] 3.1 Implement `isTelemetryEnabled()` checking `OPENSPEC_TELEMETRY`, `DO_NOT_TRACK`, and `CI` env vars
|
||||
- [x] 3.2 Implement `getOrCreateAnonymousId()` with lazy UUID generation
|
||||
- [x] 3.3 Initialize PostHog client with `flushAt: 1` and `flushInterval: 0`
|
||||
- [x] 3.4 Implement `trackCommand(commandName, version)` with `$ip: null`
|
||||
- [x] 3.5 Implement `shutdown()` with try/catch for silent failure handling
|
||||
|
||||
## 4. First-Run Notice
|
||||
|
||||
- [x] 4.1 Implement `maybeShowTelemetryNotice()` function
|
||||
- [x] 4.2 Check `noticeSeen` flag before displaying notice
|
||||
- [x] 4.3 Display notice text: "Note: OpenSpec collects anonymous usage stats. Opt out: OPENSPEC_TELEMETRY=0"
|
||||
- [x] 4.4 Update `noticeSeen` in config after first display
|
||||
|
||||
## 5. CLI Integration
|
||||
|
||||
- [x] 5.1 Add Commander.js `preAction` hook to show notice and track command
|
||||
- [x] 5.2 Add Commander.js `postAction` hook to call shutdown
|
||||
- [x] 5.3 Handle subcommand path extraction (e.g., `change:apply`)
|
||||
|
||||
## 6. Testing
|
||||
|
||||
- [x] 6.1 Test opt-out via `OPENSPEC_TELEMETRY=0`
|
||||
- [x] 6.2 Test opt-out via `DO_NOT_TRACK=1`
|
||||
- [x] 6.3 Test auto-disable in CI environment
|
||||
- [x] 6.4 Test first-run notice display and noticeSeen persistence
|
||||
- [x] 6.5 Test anonymous ID generation and persistence
|
||||
- [x] 6.6 Test silent failure on network error (mock PostHog)
|
||||
|
||||
## 7. Documentation
|
||||
|
||||
- [x] 7.1 Add telemetry disclosure section to README
|
||||
- [x] 7.2 Document opt-out methods (`OPENSPEC_TELEMETRY=0`, `DO_NOT_TRACK=1`)
|
||||
- [x] 7.3 Document what data is collected and not collected
|
||||
@@ -0,0 +1,16 @@
|
||||
## Why
|
||||
|
||||
CodeBuddy slash command configurator currently uses inconsistent frontmatter fields compared to other tools. It uses `category` and `tags` fields (like Crush) but should use `argument-hint` field (like Factory, Auggie, and Codex) for better consistency. Additionally, the `proposal` command is missing frontmatter fields entirely. After reviewing CodeBuddy's official documentation, the correct format should use `description` and `argument-hint` fields with square bracket parameter format.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Replace `category` and `tags` fields with `argument-hint` field in CodeBuddy frontmatter
|
||||
- Add missing frontmatter fields to the `proposal` command
|
||||
- Use correct square bracket format for `argument-hint` parameters (e.g., `[change-id]`)
|
||||
- Ensure consistency with CodeBuddy's official documentation
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: cli-init, cli-update
|
||||
- Affected code: `src/core/configurators/slash/codebuddy.ts`
|
||||
- CodeBuddy users will get proper argument hints in the correct format for slash commands
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Slash Command Configuration
|
||||
|
||||
The init command SHALL generate slash command files for supported editors using shared templates.
|
||||
|
||||
#### Scenario: Generating slash commands for Antigravity
|
||||
- **WHEN** the user selects Antigravity during initialization
|
||||
- **THEN** create `.agent/workflows/openspec-proposal.md`, `.agent/workflows/openspec-apply.md`, and `.agent/workflows/openspec-archive.md`
|
||||
- **AND** ensure each file begins with YAML frontmatter that contains only a `description: <stage summary>` field followed by the shared OpenSpec workflow instructions wrapped in managed markers
|
||||
- **AND** populate the workflow body with the same proposal/apply/archive guidance used for other tools so Antigravity behaves like Windsurf while pointing to the `.agent/workflows/` directory
|
||||
|
||||
#### Scenario: Generating slash commands for Claude Code
|
||||
- **WHEN** the user selects Claude Code during initialization
|
||||
- **THEN** create `.claude/commands/openspec/proposal.md`, `.claude/commands/openspec/apply.md`, and `.claude/commands/openspec/archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for CodeBuddy Code
|
||||
- **WHEN** the user selects CodeBuddy Code during initialization
|
||||
- **THEN** create `.codebuddy/commands/openspec/proposal.md`, `.codebuddy/commands/openspec/apply.md`, and `.codebuddy/commands/openspec/archive.md`
|
||||
- **AND** populate each file from shared templates that include CodeBuddy-compatible YAML frontmatter for the `description` and `argument-hint` fields
|
||||
- **AND** use square bracket format for `argument-hint` parameters (e.g., `[change-id]`)
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Cline
|
||||
- **WHEN** the user selects Cline during initialization
|
||||
- **THEN** create `.clinerules/workflows/openspec-proposal.md`, `.clinerules/workflows/openspec-apply.md`, and `.clinerules/workflows/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** include Cline-specific Markdown heading frontmatter
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Crush
|
||||
- **WHEN** the user selects Crush during initialization
|
||||
- **THEN** create `.crush/commands/openspec/proposal.md`, `.crush/commands/openspec/apply.md`, and `.crush/commands/openspec/archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** include Crush-specific frontmatter with OpenSpec category and tags
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Cursor
|
||||
- **WHEN** the user selects Cursor during initialization
|
||||
- **THEN** create `.cursor/commands/openspec-proposal.md`, `.cursor/commands/openspec-apply.md`, and `.cursor/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Factory Droid
|
||||
- **WHEN** the user selects Factory Droid during initialization
|
||||
- **THEN** create `.factory/commands/openspec-proposal.md`, `.factory/commands/openspec-apply.md`, and `.factory/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates that include Factory-compatible YAML frontmatter for the `description` and `argument-hint` fields
|
||||
- **AND** include the `$ARGUMENTS` placeholder in the template body so droid receives any user-supplied input
|
||||
- **AND** wrap the generated content in OpenSpec managed markers so `openspec update` can safely refresh the commands
|
||||
|
||||
#### Scenario: Generating slash commands for OpenCode
|
||||
- **WHEN** the user selects OpenCode during initialization
|
||||
- **THEN** create `.opencode/commands/openspec-proposal.md`, `.opencode/commands/openspec-apply.md`, and `.opencode/commands/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Windsurf
|
||||
- **WHEN** the user selects Windsurf during initialization
|
||||
- **THEN** create `.windsurf/workflows/openspec-proposal.md`, `.windsurf/workflows/openspec-apply.md`, and `.windsurf/workflows/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Kilo Code
|
||||
- **WHEN** the user selects Kilo Code during initialization
|
||||
- **THEN** create `.kilocode/workflows/openspec-proposal.md`, `.kilocode/workflows/openspec-apply.md`, and `.kilocode/workflows/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates (wrapped in OpenSpec markers) so workflow text matches other tools
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
|
||||
#### Scenario: Generating slash commands for Codex
|
||||
- **WHEN** the user selects Codex during initialization
|
||||
- **THEN** create global prompt files at `~/.codex/prompts/openspec-proposal.md`, `~/.codex/prompts/openspec-apply.md`, and `~/.codex/prompts/openspec-archive.md` (or under `$CODEX_HOME/prompts` if set)
|
||||
- **AND** populate each file from shared templates that map the first numbered placeholder (`$1`) to the primary user input (e.g., change identifier or question text)
|
||||
- **AND** wrap the generated content in OpenSpec markers so `openspec update` can refresh the prompts without touching surrounding custom notes
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Slash Command Updates
|
||||
|
||||
The update command SHALL refresh existing slash command files for configured tools without creating new ones, and ensure the OpenCode archive command accepts change ID arguments.
|
||||
|
||||
#### Scenario: Updating slash commands for Antigravity
|
||||
- **WHEN** `.agent/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh the OpenSpec-managed portion of each file so the workflow copy matches other tools while preserving the existing single-field `description` frontmatter
|
||||
- **AND** skip creating any missing workflow files during update, mirroring the behavior for Windsurf and other IDEs
|
||||
|
||||
#### Scenario: Updating slash commands for Claude Code
|
||||
- **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for CodeBuddy Code
|
||||
- **WHEN** `.codebuddy/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md`
|
||||
- **THEN** refresh each file using the shared CodeBuddy templates that include YAML frontmatter for the `description` and `argument-hint` fields
|
||||
- **AND** use square bracket format for `argument-hint` parameters (e.g., `[change-id]`)
|
||||
- **AND** preserve any user customizations outside the OpenSpec managed markers
|
||||
|
||||
#### Scenario: Updating slash commands for Cline
|
||||
- **WHEN** `.clinerules/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** include Cline-specific Markdown heading frontmatter
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Crush
|
||||
- **WHEN** `.crush/commands/` contains `openspec/proposal.md`, `openspec/apply.md`, and `openspec/archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** include Crush-specific frontmatter with OpenSpec category and tags
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Cursor
|
||||
- **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
|
||||
#### Scenario: Updating slash commands for Factory Droid
|
||||
- **WHEN** `.factory/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using the shared Factory templates that include YAML frontmatter for the `description` and `argument-hint` fields
|
||||
- **AND** ensure the template body retains the `$ARGUMENTS` placeholder so user input keeps flowing into droid
|
||||
- **AND** update only the content inside the OpenSpec managed markers, leaving any unmanaged notes untouched
|
||||
- **AND** skip creating missing files during update
|
||||
|
||||
#### Scenario: Updating slash commands for OpenCode
|
||||
- **WHEN** `.opencode/command/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
- **AND** ensure the archive command includes `$ARGUMENTS` placeholder in frontmatter for accepting change ID arguments
|
||||
|
||||
#### Scenario: Updating slash commands for Windsurf
|
||||
- **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md`
|
||||
- **THEN** refresh each file using shared templates
|
||||
- **AND** ensure templates include instructions for the relevant workflow stage
|
||||
@@ -0,0 +1,6 @@
|
||||
## 1. Implementation
|
||||
|
||||
- [x] 1.1 Update CodeBuddy frontmatter to use `argument-hint` instead of `category` and `tags`
|
||||
- [x] 1.2 Add missing frontmatter fields to the `proposal` command
|
||||
- [x] 1.3 Ensure all three commands (proposal, apply, archive) have consistent frontmatter structure
|
||||
- [x] 1.4 Test the changes by running `openspec init` and `openspec update`
|
||||
@@ -0,0 +1,206 @@
|
||||
# Design: Nix CI Validation
|
||||
|
||||
## Context
|
||||
|
||||
OpenSpec recently added Nix flake support to enable Nix users to install the tool. This includes:
|
||||
- `flake.nix`: Nix package definition with pnpm dependency fetching
|
||||
- `scripts/update-flake.sh`: Automation script to update version and hash when releasing
|
||||
|
||||
Currently, there is no CI validation ensuring these Nix artifacts remain functional. The existing CI workflow (.github/workflows/ci.yml) validates Node.js builds, tests, and linting across multiple platforms (Linux, macOS, Windows) but does not validate Nix builds.
|
||||
|
||||
**Stakeholders**: Nix users, maintainers, contributors who need confidence that Nix support works.
|
||||
|
||||
**Constraints**:
|
||||
- Must work in GitHub Actions Linux runners
|
||||
- Should minimize CI runtime impact (<5 minutes added)
|
||||
- Should support local testing with `act` for rapid iteration
|
||||
- Must integrate with existing required checks
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals**:
|
||||
- Validate `nix build` succeeds on every PR/push
|
||||
- Validate `scripts/update-flake.sh` executes without errors
|
||||
- Ensure Nix support doesn't regress silently
|
||||
- Support local testing with `act`
|
||||
- Optimize with caching to minimize CI time
|
||||
|
||||
**Non-Goals**:
|
||||
- Testing on macOS (GitHub-hosted macOS runners are slower and more expensive; Nix flake already declares macOS support)
|
||||
- Building for all declared systems (x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin) - focus on most common platform
|
||||
- Validating Nix flake quality/style (nixpkgs-fmt, etc.) - can be added later if needed
|
||||
- Running OpenSpec's full test suite through Nix build - existing CI already does this
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision 1: Use DeterminateSystems nix-installer-action
|
||||
|
||||
**What**: Use `determinatesystems/nix-installer-action` for installing Nix in CI.
|
||||
|
||||
**Why**:
|
||||
- Official GitHub Action maintained by Determinate Systems (Nix experts)
|
||||
- Handles GitHub Actions environment quirks automatically
|
||||
- Includes automatic caching configuration
|
||||
- More reliable than curl | sh installation script
|
||||
- Better error messages and diagnostics
|
||||
|
||||
**Alternatives considered**:
|
||||
- Official Nix installer (`curl -L https://nixos.org/nix/install | sh`): Works but requires manual setup of flakes, caching, and CI-specific configuration
|
||||
- `cachix/install-nix-action`: Popular alternative but determinatesystems is more actively maintained and has better GHA integration
|
||||
|
||||
### Decision 2: Use Magic Nix Cache for performance
|
||||
|
||||
**What**: Use `determinatesystems/magic-nix-cache-action` for automatic binary caching.
|
||||
|
||||
**Why**:
|
||||
- Zero-configuration caching for Nix store
|
||||
- Significantly reduces CI time on subsequent runs (from ~5min to ~1-2min)
|
||||
- Free for public repositories
|
||||
- Handles cache keys automatically
|
||||
|
||||
**Alternatives considered**:
|
||||
- Manual Nix store caching with GitHub Actions cache: More complex, requires manual cache key management
|
||||
- Cachix: Excellent tool but requires account setup and token management
|
||||
- No caching: Acceptable for initial implementation, but poor developer experience
|
||||
|
||||
### Decision 3: Separate job for Nix validation
|
||||
|
||||
**What**: Create a dedicated `nix-validate` job in .github/workflows/ci.yml that runs in parallel with other jobs.
|
||||
|
||||
**Why**:
|
||||
- Keeps Nix validation isolated from Node.js validation
|
||||
- Allows parallel execution for faster CI
|
||||
- Easier to debug when Nix-specific issues occur
|
||||
- Can be marked as required check independently
|
||||
|
||||
**Alternatives considered**:
|
||||
- Add Nix steps to existing jobs: Creates coupling between Node.js and Nix validation, harder to maintain
|
||||
- Separate workflow file: Overkill for a single job, harder to manage required checks
|
||||
|
||||
### Decision 4: Validate update script by executing it
|
||||
|
||||
**What**: Run `scripts/update-flake.sh` as part of CI validation.
|
||||
|
||||
**Why**:
|
||||
- Ensures the script doesn't break due to changes in package.json format, nix build output, or dependencies
|
||||
- Tests the full workflow users will follow when releasing
|
||||
- Catches errors early
|
||||
|
||||
**Implementation approach**:
|
||||
- Execute script in a way that doesn't modify git state (or discard changes after)
|
||||
- Verify script exits with code 0
|
||||
- Optionally validate that flake.nix contains expected patterns after execution
|
||||
|
||||
**Alternatives considered**:
|
||||
- Mock/dry-run mode: Would require modifying the script significantly
|
||||
- Skip validation: Risky - script could break and only be discovered at release time
|
||||
- Only run on release branches: Misses issues early in development
|
||||
|
||||
### Decision 5: Run on pull_request and push to main
|
||||
|
||||
**What**: Configure Nix validation job to run on:
|
||||
- `pull_request` events (any PR to main)
|
||||
- `push` events (direct pushes to main)
|
||||
- `workflow_dispatch` (manual trigger for testing)
|
||||
|
||||
**Why**:
|
||||
- Catches issues before merge (pull_request)
|
||||
- Validates main branch stays healthy (push)
|
||||
- Allows manual testing without creating PRs (workflow_dispatch)
|
||||
|
||||
### Decision 6: Support act for local testing
|
||||
|
||||
**What**: Ensure workflow is compatible with `act` tool for local CI testing.
|
||||
|
||||
**Why**:
|
||||
- Faster iteration when developing CI changes
|
||||
- Allows testing without pushing to GitHub
|
||||
- Reduces commit noise from CI debugging
|
||||
|
||||
**Requirements**:
|
||||
- Use standard GitHub Actions syntax
|
||||
- Document any act-specific configuration needed
|
||||
- Test that Nix can be installed in act's Docker containers
|
||||
|
||||
**Limitations**:
|
||||
- act may not perfectly replicate GitHub's runners, but close enough for validation
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
### Risk: CI runtime increase
|
||||
|
||||
**Impact**: Adding Nix validation will increase total CI time by 2-5 minutes per run.
|
||||
|
||||
**Mitigation**:
|
||||
- Run Nix job in parallel with existing jobs (no blocking delay)
|
||||
- Use magic-nix-cache for subsequent runs (~1-2 min with cache)
|
||||
- Configure appropriate timeout (10 minutes max)
|
||||
|
||||
**Acceptance**: The benefit of preventing Nix regressions outweighs the cost.
|
||||
|
||||
### Risk: Nix installer failures in CI
|
||||
|
||||
**Impact**: Transient failures in Nix installation could block PRs.
|
||||
|
||||
**Mitigation**:
|
||||
- Use determinatesystems action which has retry logic
|
||||
- Monitor for flaky failures and adjust if needed
|
||||
- Document troubleshooting steps
|
||||
|
||||
**Acceptance**: Nix installation is generally stable in GHA; this is low risk.
|
||||
|
||||
### Risk: Update script modifies git state
|
||||
|
||||
**Impact**: Running update-flake.sh modifies flake.nix, which could cause CI to fail if git state is checked.
|
||||
|
||||
**Mitigation**:
|
||||
- Run script in isolation without committing changes
|
||||
- Add `git checkout -- flake.nix` after validation
|
||||
- Or accept dirty git state in CI (doesn't affect build validation)
|
||||
|
||||
**Acceptance**: Script validation is important enough to handle this carefully.
|
||||
|
||||
### Risk: act compatibility issues
|
||||
|
||||
**Impact**: Workflow might not work perfectly with act due to Docker environment differences.
|
||||
|
||||
**Mitigation**:
|
||||
- Document known limitations
|
||||
- Focus on GitHub Actions as primary validation target
|
||||
- Use act as best-effort local testing
|
||||
|
||||
**Acceptance**: act support is nice-to-have, not required.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
### Phase 1: Add Nix job (new, non-required)
|
||||
1. Add `nix-validate` job to .github/workflows/ci.yml
|
||||
2. Configure to run in parallel with existing jobs
|
||||
3. Do NOT mark as required check initially
|
||||
4. Monitor for ~1 week to ensure stability
|
||||
|
||||
### Phase 2: Make required
|
||||
1. After validation is stable, add to required checks
|
||||
2. Update branch protection rules in GitHub settings
|
||||
3. Document in CONTRIBUTING.md or README
|
||||
|
||||
### Rollback Plan
|
||||
If Nix validation causes issues:
|
||||
1. Remove job from required checks in GitHub settings (immediate)
|
||||
2. Comment out or remove job from workflow (permanent fix)
|
||||
3. Investigate and fix issues
|
||||
4. Re-enable following same phased approach
|
||||
|
||||
## Open Questions
|
||||
|
||||
- **Q**: Should we test update-flake.sh on every CI run, or only when package.json or pnpm-lock.yaml changes?
|
||||
- **A**: Test on every run for simplicity. The script is fast (<30 seconds) and catching regressions is valuable.
|
||||
|
||||
- **Q**: Should we validate on macOS as well?
|
||||
- **A**: No for initial implementation. Linux validation is sufficient and macOS runners are slower/more expensive. Can add later if users report macOS-specific issues.
|
||||
|
||||
- **Q**: Should we run full OpenSpec tests through the Nix build?
|
||||
- **A**: No. The Nix build already runs `pnpm test` as part of its build phase. Existing CI jobs cover testing thoroughly. Nix validation focuses on build success.
|
||||
|
||||
- **Q**: What timeout should we use for the Nix validation job?
|
||||
- **A**: Start with 10 minutes. With caching, jobs should complete in 1-3 minutes. Without cache (first run), 5-7 minutes is expected.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Add Nix CI Validation
|
||||
|
||||
## Why
|
||||
|
||||
The project recently added Nix flake support (flake.nix) and an automated update script (scripts/update-flake.sh) to enable Nix users to install OpenSpec. However, there is no CI validation ensuring these Nix artifacts continue to work as the project evolves. This creates risk that breaking changes could be merged without detection.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add a new GitHub Actions workflow job to validate Nix flake builds successfully
|
||||
- Add validation that the update-flake.sh script executes without errors
|
||||
- Test on Linux (where Nix support is most common)
|
||||
- Ensure CI fails if Nix build or update script breaks
|
||||
- Enable local testing with `act` for developers
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: New capability `ci-nix-validation`
|
||||
- Affected code: `.github/workflows/ci.yml` (add new job)
|
||||
- Affected infrastructure: GitHub Actions runners with Nix installed
|
||||
- Benefits: Prevents regressions in Nix support, gives confidence to Nix users
|
||||
- Trade-offs: Adds ~2-3 minutes to CI runtime
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
# CI Nix Validation Specification
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Nix Flake Build Validation
|
||||
|
||||
The CI system SHALL validate that the Nix flake builds successfully on every pull request and push to main.
|
||||
|
||||
#### Scenario: Successful flake build
|
||||
|
||||
- **WHEN** a pull request or push to main is made
|
||||
- **THEN** the CI SHALL execute `nix build` and verify it completes with exit code 0
|
||||
- **AND** the build output SHALL contain the openspec binary
|
||||
|
||||
#### Scenario: Flake build failure
|
||||
|
||||
- **WHEN** the Nix flake configuration is broken
|
||||
- **THEN** the CI job SHALL fail with a non-zero exit code
|
||||
- **AND** the CI SHALL prevent merging of the pull request
|
||||
|
||||
#### Scenario: Multi-platform support check
|
||||
|
||||
- **WHEN** the flake declares support for multiple systems
|
||||
- **THEN** the CI SHALL validate the flake builds on at least Linux (x86_64-linux)
|
||||
|
||||
### Requirement: Update Script Validation
|
||||
|
||||
The CI system SHALL validate that the update-flake.sh script executes successfully and produces valid output.
|
||||
|
||||
#### Scenario: Update script execution
|
||||
|
||||
- **WHEN** the CI runs the update script validation
|
||||
- **THEN** the script SHALL execute without errors
|
||||
- **AND** the script SHALL correctly extract the version from package.json
|
||||
- **AND** the script SHALL update flake.nix with the correct version
|
||||
|
||||
#### Scenario: Update script with mock hash
|
||||
|
||||
- **WHEN** validating the update script in CI
|
||||
- **THEN** the script SHALL be able to detect and extract the correct pnpm dependency hash
|
||||
- **AND** the flake.nix SHALL be updated with a valid sha256 hash
|
||||
|
||||
### Requirement: CI Job Integration
|
||||
|
||||
The Nix validation jobs SHALL be integrated into the existing GitHub Actions workflow and required for merge.
|
||||
|
||||
#### Scenario: PR merge requirements
|
||||
|
||||
- **WHEN** a pull request is created
|
||||
- **THEN** the Nix validation job SHALL be included in required checks
|
||||
- **AND** the PR SHALL NOT be mergeable until Nix validation passes
|
||||
|
||||
#### Scenario: Job execution triggers
|
||||
|
||||
- **WHEN** code is pushed to a pull request OR pushed to main OR manually triggered
|
||||
- **THEN** the Nix validation job SHALL execute automatically
|
||||
|
||||
### Requirement: Local Testing Support
|
||||
|
||||
The CI workflow SHALL be testable locally using the `act` tool to enable rapid iteration.
|
||||
|
||||
#### Scenario: Local CI execution with act
|
||||
|
||||
- **WHEN** a developer runs `act` with the Nix validation workflow
|
||||
- **THEN** the workflow SHALL execute in the local Docker environment
|
||||
- **AND** the developer SHALL receive feedback on Nix build status without pushing to GitHub
|
||||
|
||||
#### Scenario: Act configuration compatibility
|
||||
|
||||
- **WHEN** the workflow is designed
|
||||
- **THEN** it SHALL use standard GitHub Actions syntax compatible with `act`
|
||||
- **AND** any Nix-specific setup SHALL work in the act Docker environment
|
||||
|
||||
### Requirement: Nix Installation in CI
|
||||
|
||||
The CI environment SHALL have Nix properly installed and configured before running validation.
|
||||
|
||||
#### Scenario: Nix installation step
|
||||
|
||||
- **WHEN** the Nix validation job starts
|
||||
- **THEN** Nix SHALL be installed using the official Nix installer or determinatesystems/nix-installer-action
|
||||
- **AND** the Nix installation SHALL be cached for subsequent runs to improve performance
|
||||
|
||||
#### Scenario: Nix configuration for CI
|
||||
|
||||
- **WHEN** Nix is installed in CI
|
||||
- **THEN** it SHALL be configured to work in the GitHub Actions environment
|
||||
- **AND** experimental features (flakes, nix-command) SHALL be enabled
|
||||
|
||||
### Requirement: CI Performance Optimization
|
||||
|
||||
The Nix validation SHALL be optimized to minimize CI runtime impact.
|
||||
|
||||
#### Scenario: Acceptable runtime
|
||||
|
||||
- **WHEN** the Nix validation job runs
|
||||
- **THEN** it SHALL complete in under 5 minutes on a clean run
|
||||
- **AND** with caching, it SHALL complete in under 3 minutes on subsequent runs
|
||||
|
||||
#### Scenario: Parallel execution
|
||||
|
||||
- **WHEN** multiple CI jobs are running
|
||||
- **THEN** the Nix validation job SHALL run in parallel with other validation jobs (tests, lint)
|
||||
- **AND** SHALL NOT block other independent checks
|
||||
@@ -0,0 +1,49 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. Add Nix Installation to CI
|
||||
|
||||
- [x] 1.1 Research Nix installation options for GitHub Actions (nix-installer-action vs manual install)
|
||||
- [x] 1.2 Add Nix installation step to .github/workflows/ci.yml
|
||||
- [x] 1.3 Configure Nix with experimental features enabled (flakes, nix-command)
|
||||
- [x] 1.4 Add Nix store caching to improve CI performance
|
||||
|
||||
## 2. Create Nix Build Validation Job
|
||||
|
||||
- [x] 2.1 Add new `nix-flake-validate` job to .github/workflows/ci.yml
|
||||
- [x] 2.2 Implement `nix build` step with proper error handling
|
||||
- [x] 2.3 Add verification step to confirm binary exists in build output
|
||||
- [x] 2.4 Add step to test binary execution (`nix run . -- --version`)
|
||||
|
||||
## 3. Add Update Script Validation
|
||||
|
||||
- [x] 3.1 Add job step to run scripts/update-flake.sh in dry-run or test mode
|
||||
- [x] 3.2 Verify script executes without errors
|
||||
- [x] 3.3 Add validation that version is correctly extracted from package.json
|
||||
- [x] 3.4 Verify flake.nix is updated with correct format (version and hash)
|
||||
|
||||
## 4. Configure Job Dependencies and Requirements
|
||||
|
||||
- [x] 4.1 Configure Nix validation job to run on pull_request and push events
|
||||
- [x] 4.2 Add Nix validation to required checks list
|
||||
- [x] 4.3 Configure job to run in parallel with existing test/lint jobs
|
||||
- [x] 4.4 Set appropriate timeout (5-10 minutes)
|
||||
|
||||
## 5. Test with act Locally
|
||||
|
||||
- [x] 5.1 Install act locally if not already available
|
||||
- [x] 5.2 Test Nix validation job using `act pull_request`
|
||||
- [x] 5.3 Verify act can run the workflow with Nix installed
|
||||
- [x] 5.4 Document any act-specific configuration needed in .actrc or README
|
||||
|
||||
## 6. Documentation and Finalization
|
||||
|
||||
- [x] 6.1 Add documentation about Nix CI validation to README or CONTRIBUTING.md
|
||||
- [x] 6.2 Document how to test CI locally with act
|
||||
- [ ] 6.3 Update CI badge or status indicators if needed
|
||||
- [ ] 6.4 Test end-to-end by creating a test PR
|
||||
|
||||
## 7. Archive Change
|
||||
|
||||
- [x] 7.1 After merge and verification, create new spec file at openspec/specs/ci-nix-validation/spec.md
|
||||
- [x] 7.2 Move change directory to openspec/changes/archive/[date]-add-nix-ci-validation/
|
||||
- [x] 7.3 Run `openspec validate --strict` to confirm archived change passes
|
||||
@@ -1,11 +0,0 @@
|
||||
# Delta for CLI Init
|
||||
|
||||
## MODIFIED Requirements
|
||||
### Requirement: Slash Command Configuration
|
||||
|
||||
#### Scenario: Generating slash commands for Cline
|
||||
- **WHEN** the user selects Cline during initialization
|
||||
- **THEN** create `.clinerules/workflows/openspec-proposal.md`, `.clinerules/workflows/openspec-apply.md`, and `.clinerules/workflows/openspec-archive.md`
|
||||
- **AND** populate each file from shared templates so command text matches other tools
|
||||
- **AND** include Cline-specific Markdown heading frontmatter
|
||||
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
|
||||
@@ -1,12 +0,0 @@
|
||||
## Why
|
||||
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.
|
||||
|
||||
## What Changes
|
||||
- Make change validation scope-aware: validate only artifacts that exist.
|
||||
- Only error on "No deltas found" if spec delta files exist but parse to zero deltas.
|
||||
- Keep archive stricter: if specs exist but parse to zero deltas, fail; allow `--skip-specs` for tooling-only changes.
|
||||
|
||||
## Impact
|
||||
- Affected specs: cli-validate
|
||||
- Affected code: `src/commands/validate.ts`, `src/core/validation/validator.ts`
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
## ADDED Requirements
|
||||
### Requirement: Scope-Aware Change Validation
|
||||
The validator SHALL validate only artifacts that exist for a change, avoiding errors for proposal-only or tooling-only changes.
|
||||
|
||||
#### Scenario: Proposal-only change
|
||||
- **WHEN** a change contains `proposal.md` but has no `specs/` directory or contains no `*/spec.md` files
|
||||
- **THEN** validate the proposal (Why/What sections)
|
||||
- **AND** do not require or validate spec deltas
|
||||
|
||||
#### Scenario: Delta validation when specs exist
|
||||
- **WHEN** a change contains one or more `specs/<capability>/spec.md` files
|
||||
- **THEN** validate delta-formatted specs with existing rules (SHALL/MUST, scenarios, duplicates, conflicts)
|
||||
|
||||
## MODIFIED Requirements
|
||||
### Requirement: Validation SHALL provide actionable remediation steps
|
||||
Validation output SHALL include specific guidance to fix each error, including expected structure, example headers, and suggested commands to verify fixes.
|
||||
|
||||
#### Scenario: No deltas found in change
|
||||
- **WHEN** validating a change that contains `specs/` with one or more `*/spec.md` files but the parser finds zero deltas
|
||||
- **THEN** show error "No deltas found" with guidance:
|
||||
- Ensure `openspec/changes/{id}/specs/` has `.md` files that include delta headers
|
||||
- Use delta headers: `## ADDED Requirements`, `## MODIFIED Requirements`, `## REMOVED Requirements`, `## RENAMED Requirements`
|
||||
- Each requirement must include at least one `#### Scenario:` block
|
||||
- Try: `openspec change show {id} --json --deltas-only` to inspect parsed deltas
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
## 1. Validator changes
|
||||
- [ ] 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
|
||||
- [ ] 1.2 Return valid (no error) when `specs/` directory is missing or has no `spec.md` files
|
||||
|
||||
## 2. CLI changes
|
||||
- [ ] 2.1 In bulk validation, keep current behavior (call delta validator). Behavior remains correct after 1.1
|
||||
- [ ] 2.2 Add a short INFO log in human-readable mode when a change has no `specs/` (optional)
|
||||
|
||||
## 3. Documentation
|
||||
- [ ] 3.1 Update README and template: "Validation checks only existing artifacts. Proposal-only changes are valid without spec deltas."
|
||||
|
||||
## 4. Tests
|
||||
- [ ] 4.1 Add test: proposal-only change passes validation without deltas
|
||||
- [ ] 4.2 Add test: specs present but zero parsed deltas → ERROR
|
||||
- [ ] 4.3 Add test: specs present with proper deltas → valid
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-01-23
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user