mirror of
https://github.com/Fission-AI/OpenSpec.git
synced 2026-10-04 06:18:24 +08:00
Compare commits
390
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ee9e56305 | ||
|
|
bb9f6ce0ea | ||
|
|
ae85a7229d | ||
|
|
504c93bdf1 | ||
|
|
c4a54a8d54 | ||
|
|
38d2356836 | ||
|
|
3f67debf65 | ||
|
|
533cb0fa87 | ||
|
|
8dfd824477 | ||
|
|
3ed1270316 | ||
|
|
eb15cdb983 | ||
|
|
cd172a4427 | ||
|
|
b7f5a429de | ||
|
|
a5c10ed5e7 | ||
|
|
1bc849554c | ||
|
|
d73705736f | ||
|
|
ed924ffcff | ||
|
|
1786684af6 | ||
|
|
51fb10db5e | ||
|
|
cac54042ce | ||
|
|
c47cdaafe2 | ||
|
|
ea5aa0e562 | ||
|
|
48b5ed9657 | ||
|
|
fb7ff527a6 | ||
|
|
11e195575f | ||
|
|
ab47cc6b00 | ||
|
|
8dcd1707ee | ||
|
|
4f4af5708d | ||
|
|
9822576770 | ||
|
|
af273b8e0b | ||
|
|
3ceef2db72 | ||
|
|
2c2599b1f0 | ||
|
|
c08a53cb21 | ||
|
|
455c65f3c4 | ||
|
|
9ac6330430 | ||
|
|
fb264bcbcd | ||
|
|
a2757e7856 | ||
|
|
6d84924c18 | ||
|
|
6de04f3b2b | ||
|
|
c2a1a4c807 | ||
|
|
2e71835d23 | ||
|
|
971f8ca4a3 | ||
|
|
68e0a7e68e | ||
|
|
f39cc5c1fb | ||
|
|
5129a8cf96 | ||
|
|
4ff893048d | ||
|
|
cefb4719aa | ||
|
|
5e1cef3b3b | ||
|
|
1adf3cea88 | ||
|
|
6d3cfe0443 | ||
|
|
17d1e5db3f | ||
|
|
3f5a66d3e4 | ||
|
|
c08fbc1ba0 | ||
|
|
938d03be9a | ||
|
|
19ccaabfc7 | ||
|
|
2e382b9898 | ||
|
|
b5a7d096f0 | ||
|
|
c54079a0cd | ||
|
|
1050e57ae4 | ||
|
|
17d7e59343 | ||
|
|
4758c5c68d | ||
|
|
c4b0826da7 | ||
|
|
537e6078b7 | ||
|
|
5439ab0833 | ||
|
|
9b6a763eb8 | ||
|
|
d32e50fe36 | ||
|
|
8386b91a71 | ||
|
|
8f9c3c7d0b | ||
|
|
9cdb0743f2 | ||
|
|
4e93d7a881 | ||
|
|
c4b6be41c1 | ||
|
|
a66580735c | ||
|
|
fb1d37e56e | ||
|
|
cf0de5e569 | ||
|
|
92b45462c6 | ||
|
|
5ab438f5fd | ||
|
|
5855fa2353 | ||
|
|
668a125d4d | ||
|
|
fef961f6e3 | ||
|
|
3677e0175f | ||
|
|
3ddf2586b4 | ||
|
|
ece61a6d68 | ||
|
|
ecddffc22e | ||
|
|
822464ec44 | ||
|
|
67ab683105 | ||
|
|
f82e243551 | ||
|
|
88b260d51f | ||
|
|
ce7422209f | ||
|
|
63b8a3e9f9 | ||
|
|
4cf7bf863d | ||
|
|
b30882b579 | ||
|
|
082abb4795 | ||
|
|
b81fa1e6cc | ||
|
|
4a863285b0 | ||
|
|
fe83be5d61 | ||
|
|
345f9dbb45 | ||
|
|
cc9d5402ff | ||
|
|
108bcd66d8 | ||
|
|
a50105e03c | ||
|
|
312e1d6d7c | ||
|
|
56d57da119 | ||
|
|
f56189a8f7 | ||
|
|
d7e0ce85e5 | ||
|
|
eb0d50c094 | ||
|
|
c482f1b47a | ||
|
|
2ae0484ac7 | ||
|
|
8c65b47abe | ||
|
|
9c9e57daa1 | ||
|
|
c7ca76cb4f | ||
|
|
06bd3999bf | ||
|
|
821097079a | ||
|
|
42e3118b0c | ||
|
|
a785c2a99a | ||
|
|
af513191eb | ||
|
|
efbbf3b9f1 | ||
|
|
6105211163 | ||
|
|
b3d31d224d | ||
|
|
9ae6141eb1 | ||
|
|
d84069a3ae | ||
|
|
8c974f8a80 | ||
|
|
25289b510d | ||
|
|
d070d08aa8 | ||
|
|
6539ceb54a | ||
|
|
c29b06da42 | ||
|
|
4a2b23942c | ||
|
|
807b9d32a6 | ||
|
|
b3d05d2f78 | ||
|
|
9848242587 | ||
|
|
5e0d21d1ed | ||
|
|
31d85d0e8b | ||
|
|
bc3666d702 | ||
|
|
970b9f6e2d | ||
|
|
5cb84a775e | ||
|
|
adc63069a9 | ||
|
|
f8eca37796 | ||
|
|
a908dc5a05 | ||
|
|
b46f99b9bc | ||
|
|
6f7cc2abd2 | ||
|
|
4867bfade5 | ||
|
|
7359b4846a | ||
|
|
88526e6b93 | ||
|
|
367aa12892 | ||
|
|
dcfb6afe0c | ||
|
|
86925b2b2d | ||
|
|
604ecb8bd1 | ||
|
|
5a4837c37d | ||
|
|
9d9539aaa2 | ||
|
|
c3fecf0619 | ||
|
|
6469593495 | ||
|
|
157936cf68 | ||
|
|
fef33df753 | ||
|
|
78b61e8466 | ||
|
|
5fa0fa68a7 | ||
|
|
fe9eb44ec2 | ||
|
|
ee78f21b08 | ||
|
|
e3ae2ceaf0 | ||
|
|
20b2fee749 | ||
|
|
e7fff31df2 | ||
|
|
fdf9a30f0b | ||
|
|
161aa41cb3 | ||
|
|
9e092a185b | ||
|
|
38454bb2a6 | ||
|
|
b04f1cc923 | ||
|
|
ae86e9be9e | ||
|
|
f955e87fd9 | ||
|
|
55efd19953 | ||
|
|
dab5d93b85 | ||
|
|
7b0f494754 | ||
|
|
dd7ba71fe5 | ||
|
|
66ad5658f9 | ||
|
|
21a0e74b74 | ||
|
|
485ef07ec7 | ||
|
|
ce5ceadbe7 | ||
|
|
9a173b917c | ||
|
|
79baabbed1 | ||
|
|
818a5922ce | ||
|
|
d8d2930182 | ||
|
|
6af6e0ccb6 | ||
|
|
50e6660018 | ||
|
|
4bbb52dda4 | ||
|
|
4a0ae49b6e | ||
|
|
5b2049aedf | ||
|
|
332020ac6b | ||
|
|
646c516b0d | ||
|
|
8c1b580f03 | ||
|
|
17e6f7166b | ||
|
|
931d10477e | ||
|
|
e4548bcc58 | ||
|
|
68fc049955 | ||
|
|
4874a16495 | ||
|
|
3caabf86cf | ||
|
|
d4593e4a54 | ||
|
|
0144ec2b1b | ||
|
|
98d90cc00d | ||
|
|
ccaa5ad0b0 | ||
|
|
8eb7ebd7cd | ||
|
|
be395d9d74 | ||
|
|
a09b87e391 | ||
|
|
9d7b44b722 | ||
|
|
44c06cc40e | ||
|
|
b33f435812 | ||
|
|
b62b57caf3 | ||
|
|
758d91613d | ||
|
|
47180e5120 | ||
|
|
8dde1d55fc | ||
|
|
3cef6f0925 | ||
|
|
82ba1f504e | ||
|
|
d54fcc97f2 | ||
|
|
ebff738860 | ||
|
|
1bdaeef4da | ||
|
|
2921676e93 | ||
|
|
792129bfe3 | ||
|
|
715ff513e3 | ||
|
|
f6913b7661 | ||
|
|
730bbc00af | ||
|
|
adfcc65b9f | ||
|
|
590541277d | ||
|
|
14e2cc628a | ||
|
|
299171c5cb | ||
|
|
bb6aae0205 | ||
|
|
23c0ab6358 | ||
|
|
02fe5b3547 | ||
|
|
57216a7824 | ||
|
|
6e210cf084 | ||
|
|
5c6ae8e407 | ||
|
|
5376030421 | ||
|
|
7d735eb2d8 | ||
|
|
4d55e9ac6d | ||
|
|
9d674b22a3 | ||
|
|
96458ced1f | ||
|
|
3d8f2a5974 | ||
|
|
006676c973 | ||
|
|
63f45c0fcf | ||
|
|
522126a6ee | ||
|
|
23b8030494 | ||
|
|
f70df96656 | ||
|
|
df12368f11 | ||
|
|
acd1ca28f3 | ||
|
|
aedf4a34af | ||
|
|
f0c52ac7e8 | ||
|
|
f933e9b144 | ||
|
|
24b4866426 | ||
|
|
b7899602b4 | ||
|
|
b66d914198 | ||
|
|
9926103505 | ||
|
|
873e45a996 | ||
|
|
573afa0c65 | ||
|
|
665d740adb | ||
|
|
c35dd38567 | ||
|
|
aa9e49612b | ||
|
|
36eb0bbbf5 | ||
|
|
d549cec121 | ||
|
|
1a3bfae784 | ||
|
|
fae08072a9 | ||
|
|
07df6c97c9 | ||
|
|
7b13a2de03 | ||
|
|
41fc14d360 | ||
|
|
7c0face31b | ||
|
|
332816cc35 | ||
|
|
7ced2a8791 | ||
|
|
a79b8b5c03 | ||
|
|
52d620e40e | ||
|
|
22082338fd | ||
|
|
6458b6ed39 | ||
|
|
01a2f5d600 | ||
|
|
95d855d641 | ||
|
|
562530dfa8 | ||
|
|
1e17cfdd0b | ||
|
|
5d185ba3a8 | ||
|
|
08b41c7bea | ||
|
|
8ac50289f0 | ||
|
|
1f295cec52 | ||
|
|
ad8e213cf9 | ||
|
|
a6c1a90165 | ||
|
|
21b5a3e680 | ||
|
|
1bda5be96c | ||
|
|
0faf44807e | ||
|
|
f9c1d07edb | ||
|
|
2bd1a4417c | ||
|
|
1db19ac3d8 | ||
|
|
25018786e4 | ||
|
|
5fd9173ad9 | ||
|
|
0a611747bc | ||
|
|
49e422724f | ||
|
|
c22d6bce1c | ||
|
|
1c0dc09dc9 | ||
|
|
f0b1e00c65 | ||
|
|
5fe72ddc5d | ||
|
|
c18f3b2b2e | ||
|
|
33344727a8 | ||
|
|
828e5ba316 | ||
|
|
31c57f5c0f | ||
|
|
767a0053e8 | ||
|
|
fd65b99c91 | ||
|
|
e170df9f41 | ||
|
|
b91040e8c2 | ||
|
|
8824bd2a42 | ||
|
|
1d3c292d94 | ||
|
|
cfe6da96ac | ||
|
|
c3c78551d0 | ||
|
|
f1fabc5f18 | ||
|
|
166b960428 | ||
|
|
ef1a6c0f0b | ||
|
|
9b3944bd09 | ||
|
|
7917d08a50 | ||
|
|
4a8e5986f0 | ||
|
|
103838f371 | ||
|
|
0a26c686f9 | ||
|
|
efcf766193 | ||
|
|
151eddb759 | ||
|
|
cb0d6f3189 | ||
|
|
a897c697a5 | ||
|
|
3bedf6b23e | ||
|
|
9ff0e85693 | ||
|
|
1ca407fa2f | ||
|
|
46c927af06 | ||
|
|
87cb206e88 | ||
|
|
6806a2fc5a | ||
|
|
4ab65d75dd | ||
|
|
2a3294dbfb | ||
|
|
8334006f2b | ||
|
|
8a559e0d00 | ||
|
|
a3924f17b2 | ||
|
|
b11e862b0f | ||
|
|
099585afcb | ||
|
|
f023fc317e | ||
|
|
38a1463af0 | ||
|
|
f2399d3280 | ||
|
|
f699e10778 | ||
|
|
c824d8927f | ||
|
|
5821b24ab3 | ||
|
|
e812eb9e78 | ||
|
|
abfe13c5a7 | ||
|
|
0d5a75d3a0 | ||
|
|
b30c0ad27e | ||
|
|
1cada18186 | ||
|
|
fa50b07938 | ||
|
|
b6cad1631c | ||
|
|
2497e81e4d | ||
|
|
d8cba03840 | ||
|
|
0b1be19302 | ||
|
|
d7ebee4555 | ||
|
|
8f45a6f6ee | ||
|
|
6da77f01ce | ||
|
|
d90eccf959 | ||
|
|
f192a97aeb | ||
|
|
7781bbadd3 | ||
|
|
aeaa1d50cc | ||
|
|
fa5df9a329 | ||
|
|
f94f396c99 | ||
|
|
1f670f71d4 | ||
|
|
32b2901d13 | ||
|
|
2ad0b1d306 | ||
|
|
279d327899 | ||
|
|
5d848cf005 | ||
|
|
5607fd3ccb | ||
|
|
6a0d862258 | ||
|
|
1fe5f84fbc | ||
|
|
80e78ecd1e | ||
|
|
564135a530 | ||
|
|
b9e80641a0 | ||
|
|
0755994eaa | ||
|
|
dcabd6de31 | ||
|
|
aef6ce01ff | ||
|
|
441f9f444b | ||
|
|
b322829091 | ||
|
|
5167e65a5c | ||
|
|
5c6b4113a7 | ||
|
|
a8b76c3e69 | ||
|
|
d3237cac7b | ||
|
|
e395eb4eeb | ||
|
|
76e1ec2a1f | ||
|
|
6cbb803e48 | ||
|
|
183b82f266 | ||
|
|
27eaccc024 | ||
|
|
b288f2fc88 | ||
|
|
22134a603b | ||
|
|
3b5fd11cb9 | ||
|
|
fce227a36e | ||
|
|
e9417fc147 | ||
|
|
8bcf2c6905 | ||
|
|
467346f9fe | ||
|
|
9a03ba1853 | ||
|
|
581a681a47 | ||
|
|
3093ca6ae6 | ||
|
|
9d425865c1 | ||
|
|
a490dbbc78 | ||
|
|
fc0e2319b1 | ||
|
|
edf6873afa | ||
|
|
c0ce4adc0a |
@@ -0,0 +1,6 @@
|
||||
This directory is managed by 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.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config/schema.json",
|
||||
"changelog": "@changesets/cli/changelog",
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"linked": [],
|
||||
"access": "public",
|
||||
"baseBranch": "main",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": []
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
|
||||
# Minimal configuration for getting started
|
||||
language: "en-US"
|
||||
reviews:
|
||||
profile: "chill"
|
||||
high_level_summary: true
|
||||
auto_review:
|
||||
enabled: true
|
||||
drafts: false
|
||||
base_branches:
|
||||
- ".*"
|
||||
@@ -0,0 +1,92 @@
|
||||
# Dev Container Setup
|
||||
|
||||
This directory contains the VS Code dev container configuration for OpenSpec development.
|
||||
|
||||
## What's Included
|
||||
|
||||
- **Node.js 20 LTS** (>=20.19.0) - TypeScript/JavaScript runtime
|
||||
- **pnpm** - Fast, disk space efficient package manager
|
||||
- **Git + GitHub CLI** - Version control tools
|
||||
- **VS Code Extensions**:
|
||||
- ESLint & Prettier for code quality
|
||||
- Vitest Explorer for running tests
|
||||
- GitLens for enhanced git integration
|
||||
- Error Lens for inline error highlighting
|
||||
- Code Spell Checker
|
||||
- Path IntelliSense
|
||||
|
||||
## How to Use
|
||||
|
||||
### First Time Setup
|
||||
|
||||
1. **Install Prerequisites** (on your local machine):
|
||||
- [VS Code](https://code.visualstudio.com/)
|
||||
- [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
||||
- [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
||||
|
||||
2. **Open in Container**:
|
||||
- Open this project in VS Code
|
||||
- You'll see a notification: "Folder contains a Dev Container configuration file"
|
||||
- Click "Reopen in Container"
|
||||
|
||||
OR
|
||||
|
||||
- Open Command Palette (`Cmd/Ctrl+Shift+P`)
|
||||
- Type "Dev Containers: Reopen in Container"
|
||||
- Press Enter
|
||||
|
||||
3. **Wait for Setup**:
|
||||
- The container will build (first time takes a few minutes)
|
||||
- `pnpm install` runs automatically via `postCreateCommand`
|
||||
- All extensions install automatically
|
||||
|
||||
### Daily Development
|
||||
|
||||
Once set up, the container preserves your development environment:
|
||||
|
||||
```bash
|
||||
# Run development build
|
||||
pnpm run dev
|
||||
|
||||
# Run CLI in development
|
||||
pnpm run dev:cli
|
||||
|
||||
# Run tests
|
||||
pnpm test
|
||||
|
||||
# Run tests in watch mode
|
||||
pnpm test:watch
|
||||
|
||||
# Build the project
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
### SSH Keys
|
||||
|
||||
Your SSH keys are mounted read-only from `~/.ssh`, so git operations work seamlessly with GitHub/GitLab.
|
||||
|
||||
### Rebuilding the Container
|
||||
|
||||
If you modify `.devcontainer/devcontainer.json`:
|
||||
- Command Palette → "Dev Containers: Rebuild Container"
|
||||
|
||||
## Benefits
|
||||
|
||||
- No need to install Node.js or pnpm on your local machine
|
||||
- Consistent development environment across team members
|
||||
- Isolated from other Node.js projects on your machine
|
||||
- All dependencies and tools containerized
|
||||
- Easy onboarding for new developers
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Container won't build:**
|
||||
- Ensure Docker Desktop is running
|
||||
- Check Docker has enough memory allocated (recommend 4GB+)
|
||||
|
||||
**Extensions not appearing:**
|
||||
- Rebuild the container: "Dev Containers: Rebuild Container"
|
||||
|
||||
**Permission issues:**
|
||||
- The container runs as the `node` user (non-root)
|
||||
- Files created in the container are owned by this user
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"name": "OpenSpec Development",
|
||||
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bookworm",
|
||||
|
||||
// Additional tools and features
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/git:1": {
|
||||
"version": "latest",
|
||||
"ppa": true
|
||||
},
|
||||
"ghcr.io/devcontainers/features/github-cli:1": {
|
||||
"version": "latest"
|
||||
}
|
||||
},
|
||||
|
||||
// Configure tool-specific properties
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
// Set default container specific settings
|
||||
"settings": {
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "explicit"
|
||||
},
|
||||
"files.eol": "\n",
|
||||
"terminal.integrated.defaultProfile.linux": "bash"
|
||||
},
|
||||
|
||||
// Add extensions you want installed when the container is created
|
||||
"extensions": [
|
||||
// TypeScript/JavaScript essentials
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
|
||||
// Testing
|
||||
"vitest.explorer",
|
||||
|
||||
// Git
|
||||
"eamodio.gitlens",
|
||||
|
||||
// Utilities
|
||||
"streetsidesoftware.code-spell-checker",
|
||||
"usernamehw.errorlens",
|
||||
"christian-kohler.path-intellisense"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created
|
||||
"postCreateCommand": "corepack enable && corepack prepare pnpm@latest --activate && pnpm install",
|
||||
|
||||
// Configure mounts to preserve SSH keys for git operations
|
||||
"mounts": [
|
||||
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/node/.ssh,readonly,type=bind,consistency=cached"
|
||||
],
|
||||
|
||||
// Set the default user to 'node' (non-root user)
|
||||
"remoteUser": "node",
|
||||
|
||||
// Ensure git is properly configured
|
||||
"initializeCommand": "echo 'Initializing dev container...'"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
# Default code ownership
|
||||
* @TabishB
|
||||
@@ -0,0 +1,225 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test_pr:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build project
|
||||
run: pnpm run build
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm test
|
||||
|
||||
- name: Upload test coverage
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-report-pr
|
||||
path: coverage/
|
||||
retention-days: 7
|
||||
|
||||
test_matrix:
|
||||
name: Test (${{ matrix.label }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 15
|
||||
if: github.event_name != 'pull_request'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
shell: bash
|
||||
label: linux-bash
|
||||
- os: macos-latest
|
||||
shell: bash
|
||||
label: macos-bash
|
||||
- os: windows-latest
|
||||
shell: pwsh
|
||||
label: windows-pwsh
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: ${{ matrix.shell }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Print environment diagnostics
|
||||
run: |
|
||||
node -p "JSON.stringify({ platform: process.platform, arch: process.arch, shell: process.env.SHELL || process.env.ComSpec || '' })"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build project
|
||||
run: pnpm run build
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm test
|
||||
|
||||
- name: Upload test coverage
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-report-main
|
||||
path: coverage/
|
||||
retention-days: 7
|
||||
|
||||
lint:
|
||||
name: Lint & Type Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build project
|
||||
run: pnpm run build
|
||||
|
||||
- name: Type check
|
||||
run: pnpm exec tsc --noEmit
|
||||
|
||||
- name: Lint
|
||||
run: pnpm lint
|
||||
|
||||
- name: Check for build artifacts
|
||||
run: |
|
||||
if [ ! -d "dist" ]; then
|
||||
echo "Error: dist directory not found after build"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "dist/cli/index.js" ]; then
|
||||
echo "Error: CLI entry point not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
validate-changesets:
|
||||
name: Validate Changesets
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Validate changesets
|
||||
run: |
|
||||
if command -v changeset &> /dev/null; then
|
||||
pnpm exec changeset status --since=origin/main
|
||||
else
|
||||
echo "Changesets not configured, skipping validation"
|
||||
fi
|
||||
|
||||
required-checks-pr:
|
||||
name: All checks passed
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test_pr, lint]
|
||||
if: always() && github.event_name == 'pull_request'
|
||||
steps:
|
||||
- name: Verify all checks passed
|
||||
run: |
|
||||
if [[ "${{ needs.test_pr.result }}" != "success" ]]; then
|
||||
echo "Test job failed"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${{ needs.lint.result }}" != "success" ]]; then
|
||||
echo "Lint job failed"
|
||||
exit 1
|
||||
fi
|
||||
echo "All required checks passed!"
|
||||
|
||||
required-checks-main:
|
||||
name: All checks passed
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test_matrix, lint]
|
||||
if: always() && github.event_name != 'pull_request'
|
||||
steps:
|
||||
- name: Verify all checks passed
|
||||
run: |
|
||||
if [[ "${{ needs.test_matrix.result }}" != "success" ]]; then
|
||||
echo "Matrix test job failed"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${{ needs.lint.result }}" != "success" ]]; then
|
||||
echo "Lint job failed"
|
||||
exit 1
|
||||
fi
|
||||
echo "All required checks passed!"
|
||||
@@ -0,0 +1,48 @@
|
||||
name: Release (prepare)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
id-token: write # Required for npm OIDC trusted publishing
|
||||
|
||||
concurrency:
|
||||
group: release-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
if: github.repository == 'Fission-AI/OpenSpec'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '24' # Node 24 includes npm 11.5.1+ required for OIDC
|
||||
cache: 'pnpm'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
# Opens/updates the Version Packages PR; publishes when the Version PR merges
|
||||
- name: Create/Update Version PR
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
title: 'chore(release): version packages'
|
||||
createGithubReleases: true
|
||||
# Use CI-specific release script: relies on version PR having been merged
|
||||
# so package.json already contains the bumped version.
|
||||
publish: pnpm run release:ci
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# npm authentication handled via OIDC trusted publishing (no token needed)
|
||||
+5
-3
@@ -140,9 +140,11 @@ dist/
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
# Internal Docs
|
||||
docs/
|
||||
|
||||
# Claude
|
||||
.claude/
|
||||
CLAUDE.md
|
||||
CLAUDE.md
|
||||
.DS_Store
|
||||
|
||||
# Pnpm
|
||||
.pnpm-store/
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<!-- 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 -->
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
# @fission-ai/openspec
|
||||
|
||||
## 0.18.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 8dfd824: Add OPSX experimental workflow commands and enhanced artifact system
|
||||
|
||||
**New Commands:**
|
||||
|
||||
- `/opsx:ff` - Fast-forward through artifact creation, generating all needed artifacts in one go
|
||||
- `/opsx:sync` - Sync delta specs from a change to main specs
|
||||
- `/opsx:archive` - Archive completed changes with smart sync check
|
||||
|
||||
**Artifact Workflow Enhancements:**
|
||||
|
||||
- Schema-aware apply instructions with inline guidance and XML output
|
||||
- Agent schema selection for experimental artifact workflow
|
||||
- Per-change schema metadata via `.openspec.yaml` files
|
||||
- Agent Skills for experimental artifact workflow
|
||||
- Instruction loader for template loading and change context
|
||||
- Restructured schemas as directories with templates
|
||||
|
||||
**Improvements:**
|
||||
|
||||
- Enhanced list command with last modified timestamps and sorting
|
||||
- Change creation utilities for better workflow support
|
||||
|
||||
**Fixes:**
|
||||
|
||||
- Normalize paths for cross-platform glob compatibility
|
||||
- Allow REMOVED requirements when creating new spec files
|
||||
|
||||
## 0.17.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 455c65f: Fix `--no-interactive` flag in validate command to properly disable spinner, preventing hangs in pre-commit hooks and CI environments
|
||||
|
||||
## 0.17.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a2757e7: Fix pre-commit hook hang issue in config command by using dynamic import for @inquirer/prompts
|
||||
|
||||
The config command was causing pre-commit hooks to hang indefinitely due to stdin event listeners being registered at module load time. This fix converts the static import to a dynamic import that only loads inquirer when the `config reset` command is actually used interactively.
|
||||
|
||||
Also adds ESLint with a rule to prevent static @inquirer imports, avoiding future regressions.
|
||||
|
||||
## 0.17.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 2e71835: ### New Features
|
||||
|
||||
- Add `openspec config` command for managing global configuration settings
|
||||
- Implement global config directory with XDG Base Directory specification support
|
||||
- Add Oh-my-zsh shell completions support for enhanced CLI experience
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix hang in pre-commit hooks by using dynamic imports
|
||||
- Respect XDG_CONFIG_HOME environment variable on all platforms
|
||||
- Resolve Windows compatibility issues in zsh-installer tests
|
||||
- Align cli-completion spec with implementation
|
||||
- Remove hardcoded agent field from slash commands
|
||||
|
||||
### Documentation
|
||||
|
||||
- Alphabetize AI tools list in README and make it collapsible
|
||||
|
||||
## 0.16.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- c08fbc1: Add new AI tool integrations and enhancements:
|
||||
|
||||
- **feat(iflow-cli)**: Add iFlow-cli integration with slash command support and documentation
|
||||
- **feat(init)**: Add IDE restart instruction after init to inform users about slash command availability
|
||||
**feat(antigravity)**: Add Antigravity slash command support
|
||||
- **fix**: Generate TOML commands for Qwen Code (fixes #293)
|
||||
- Clarify scaffold proposal documentation and enhance proposal guidelines
|
||||
- Update proposal guidelines to emphasize design-first approach before implementation
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add Antigravity slash command support so `openspec init` can generate `.agent/workflows/openspec-*.md` files with description-only frontmatter and `openspec update` refreshes existing workflows alongside Windsurf.
|
||||
|
||||
## 0.15.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 4758c5c: Add support for new AI tools with native slash command integration
|
||||
|
||||
- **Gemini CLI**: Add native TOML-based slash command support for Gemini CLI with `.gemini/commands/openspec/` integration
|
||||
- **RooCode**: Add RooCode integration with configurator, slash commands, and templates
|
||||
- **Cline**: Fix Cline to use workflows instead of rules for slash commands (`.clinerules/workflows/` paths)
|
||||
- **Documentation**: Update documentation to reflect new integrations and workflow changes
|
||||
|
||||
## 0.14.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 8386b91: Add support for new AI assistants and configuration improvements
|
||||
|
||||
- feat: add Qwen Code support with slash command integration
|
||||
- feat: add $ARGUMENTS support to apply slash command for dynamic variable passing
|
||||
- feat: add Qoder CLI support to configuration and documentation
|
||||
- feat: add CoStrict AI assistant support
|
||||
- fix: recreate missing openspec template files in extend mode
|
||||
- fix: prevent false 'already configured' detection for tools
|
||||
- fix: use change-id as fallback title instead of "Untitled Change"
|
||||
- docs: add guidance for populating project-level context
|
||||
- docs: add Crush to supported AI tools in README
|
||||
|
||||
## 0.13.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 668a125: Add support for multiple AI assistants and improve validation
|
||||
|
||||
This release adds support for several new AI coding assistants:
|
||||
|
||||
- CodeBuddy Code - AI-powered coding assistant
|
||||
- CodeRabbit - AI code review assistant
|
||||
- Cline - Claude-powered CLI assistant
|
||||
- Crush AI - AI assistant platform
|
||||
- Auggie (Augment CLI) - Code augmentation tool
|
||||
|
||||
New features:
|
||||
|
||||
- Archive slash command now supports arguments for more flexible workflows
|
||||
|
||||
Bug fixes:
|
||||
|
||||
- Delta spec validation now handles case-insensitive headers and properly detects empty sections
|
||||
- Archive validation now correctly honors --no-validate flag and ignores metadata
|
||||
|
||||
Documentation improvements:
|
||||
|
||||
- Added VS Code dev container configuration for easier development setup
|
||||
- Updated AGENTS.md with explicit change-id notation
|
||||
- Enhanced slash commands documentation with restart notes
|
||||
|
||||
## 0.12.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 082abb4: Add factory function support for slash commands and non-interactive init options
|
||||
|
||||
This release includes two new features:
|
||||
|
||||
- **Factory function support for slash commands**: Slash commands can now be defined as functions that return command objects, enabling dynamic command configuration
|
||||
- **Non-interactive init options**: Added `--tools`, `--all-tools`, and `--skip-tools` CLI flags to `openspec init` for automated initialization in CI/CD pipelines while maintaining backward compatibility with interactive mode
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 312e1d6: Add Amazon Q Developer CLI integration. OpenSpec now supports Amazon Q Developer with automatic prompt generation in `.amazonq/prompts/` directory, allowing you to use OpenSpec slash commands with Amazon Q's @-syntax.
|
||||
|
||||
## 0.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- d7e0ce8: Improve init wizard Enter key behavior to allow proceeding through prompts more naturally
|
||||
|
||||
## 0.9.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 2ae0484: Fix cross-platform path handling issues. This release includes fixes for joinPath behavior and slash command path resolution to ensure OpenSpec works correctly across all platforms.
|
||||
|
||||
## 0.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 8210970: Fix OpenSpec not working on Windows when Codex integration is selected. This release includes fixes for cross-platform path handling and normalization to ensure OpenSpec works correctly on Windows systems.
|
||||
|
||||
## 0.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- efbbf3b: Add support for Codex and GitHub Copilot slash commands with YAML frontmatter and $ARGUMENTS
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add GitHub Copilot slash command support. OpenSpec now writes prompts to `.github/prompts/openspec-{proposal,apply,archive}.prompt.md` with YAML frontmatter and `$ARGUMENTS` placeholder, and refreshes them on `openspec update`.
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d070d08: Fix CLI version mismatch and add a release guard that validates the packed tarball prints the same version as package.json via `openspec --version`.
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- c29b06d: Add Windsurf support.
|
||||
- Add Codex slash command support. OpenSpec now writes prompts directly to Codex's global directory (`~/.codex/prompts` or `$CODEX_HOME/prompts`) and refreshes them on `openspec update`.
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add native Kilo Code workflow integration so `openspec init` and `openspec update` manage `.kilocode/workflows/openspec-*.md` files.
|
||||
- Always scaffold the managed root `AGENTS.md` hand-off stub and regroup the AI tool prompts during init/update to keep instructions consistent.
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Slim the generated root agent instructions down to a managed hand-off stub and update the init/update flows to refresh it safely.
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: implement Phase 1 E2E testing with cross-platform CI matrix
|
||||
|
||||
- Add shared runCLI helper in test/helpers/run-cli.ts for spawn testing
|
||||
- Create test/cli-e2e/basic.test.ts covering help, version, validate flows
|
||||
- Migrate existing CLI exec tests to use runCLI helper
|
||||
- Extend CI matrix to bash (Linux/macOS) and pwsh (Windows)
|
||||
- Split PR and main workflows for optimized feedback
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Make apply instructions more specific
|
||||
|
||||
Improve agent templates and slash command templates with more specific and actionable apply instructions.
|
||||
|
||||
- docs: improve documentation and cleanup
|
||||
|
||||
- Document non-interactive flag for archive command
|
||||
- Replace discord badge in README
|
||||
- Archive completed changes for better organization
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add OpenSpec change proposals for CLI improvements and enhanced user experience
|
||||
- Add Opencode slash commands support for AI-driven development workflows
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Add documentation improvements including --yes flag for archive command template and Discord badge
|
||||
- Fix normalize line endings in markdown parser to handle CRLF files properly
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Enhance `openspec init` with extend mode, multi-tool selection, and an interactive `AGENTS.md` configurator.
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ce5cead: - Add an `openspec view` dashboard that rolls up spec counts and change progress at a glance
|
||||
- Generate and update AI slash commands alongside the renamed `openspec/AGENTS.md` instructions file
|
||||
- Remove the deprecated `openspec diff` command and direct users to `openspec show`
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 24b4866: Initial release
|
||||
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 OpenSpec Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -0,0 +1,423 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/Fission-AI/OpenSpec">
|
||||
<picture>
|
||||
<source srcset="assets/openspec_pixel_dark.svg" media="(prefers-color-scheme: dark)">
|
||||
<source srcset="assets/openspec_pixel_light.svg" media="(prefers-color-scheme: light)">
|
||||
<img src="assets/openspec_pixel_light.svg" alt="OpenSpec logo" height="64">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
</p>
|
||||
<p align="center">Spec-driven development for AI coding assistants.</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/Fission-AI/OpenSpec/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Fission-AI/OpenSpec/actions/workflows/ci.yml/badge.svg" /></a>
|
||||
<a href="https://www.npmjs.com/package/@fission-ai/openspec"><img alt="npm version" src="https://img.shields.io/npm/v/@fission-ai/openspec?style=flat-square" /></a>
|
||||
<a href="https://nodejs.org/"><img alt="node version" src="https://img.shields.io/node/v/@fission-ai/openspec?style=flat-square" /></a>
|
||||
<a href="./LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square" /></a>
|
||||
<a href="https://conventionalcommits.org"><img alt="Conventional Commits" src="https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg?style=flat-square" /></a>
|
||||
<a href="https://discord.gg/YctCnvvshC"><img alt="Discord" src="https://img.shields.io/badge/Discord-Join%20the%20community-5865F2?logo=discord&logoColor=white&style=flat-square" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="assets/openspec_dashboard.png" alt="OpenSpec dashboard preview" width="90%">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Follow <a href="https://x.com/0xTab">@0xTab on X</a> for updates · Join the <a href="https://discord.gg/YctCnvvshC">OpenSpec Discord</a> for help and questions.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<sub>🧪 <strong>New:</strong> <a href="docs/experimental-workflow.md">Experimental Workflow (OPSX)</a> — schema-driven, hackable, fluid. Iterate on workflows without code changes.</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.**
|
||||
|
||||
## Why OpenSpec?
|
||||
|
||||
AI coding assistants are powerful but unpredictable when requirements live in chat history. OpenSpec adds a lightweight specification workflow that locks intent before implementation, giving you deterministic, reviewable outputs.
|
||||
|
||||
Key outcomes:
|
||||
- Human and AI stakeholders agree on specs before work begins.
|
||||
- Structured change folders (proposals, tasks, and spec updates) keep scope explicit and auditable.
|
||||
- Shared visibility into what's proposed, active, or archived.
|
||||
- Works with the AI tools you already use: custom slash commands where supported, context rules everywhere else.
|
||||
|
||||
## How OpenSpec compares (at a glance)
|
||||
|
||||
- **Lightweight**: simple workflow, no API keys, minimal setup.
|
||||
- **Brownfield-first**: works great beyond 0→1. OpenSpec separates the source of truth from proposals: `openspec/specs/` (current truth) and `openspec/changes/` (proposed updates). This keeps diffs explicit and manageable across features.
|
||||
- **Change tracking**: proposals, tasks, and spec deltas live together; archiving merges the approved updates back into specs.
|
||||
- **Compared to spec-kit & Kiro**: those shine for brand-new features (0→1). OpenSpec also excels when modifying existing behavior (1→n), especially when updates span multiple specs.
|
||||
|
||||
See the full comparison in [How OpenSpec Compares](#how-openspec-compares).
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
┌────────────────────┐
|
||||
│ Draft Change │
|
||||
│ Proposal │
|
||||
└────────┬───────────┘
|
||||
│ share intent with your AI
|
||||
▼
|
||||
┌────────────────────┐
|
||||
│ Review & Align │
|
||||
│ (edit specs/tasks) │◀──── feedback loop ──────┐
|
||||
└────────┬───────────┘ │
|
||||
│ approved plan │
|
||||
▼ │
|
||||
┌────────────────────┐ │
|
||||
│ Implement Tasks │──────────────────────────┘
|
||||
│ (AI writes code) │
|
||||
└────────┬───────────┘
|
||||
│ ship the change
|
||||
▼
|
||||
┌────────────────────┐
|
||||
│ Archive & Update │
|
||||
│ Specs (source) │
|
||||
└────────────────────┘
|
||||
|
||||
1. Draft a change proposal that captures the spec updates you want.
|
||||
2. Review the proposal with your AI assistant until everyone agrees.
|
||||
3. Implement tasks that reference the agreed specs.
|
||||
4. Archive the change to merge the approved updates back into the source-of-truth specs.
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Supported AI Tools
|
||||
|
||||
<details>
|
||||
<summary><strong>Native Slash Commands</strong> (click to expand)</summary>
|
||||
|
||||
These tools have built-in OpenSpec commands. Select the OpenSpec integration when prompted.
|
||||
|
||||
| Tool | Commands |
|
||||
|------|----------|
|
||||
| **Amazon Q Developer** | `@openspec-proposal`, `@openspec-apply`, `@openspec-archive` (`.amazonq/prompts/`) |
|
||||
| **Antigravity** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.agent/workflows/`) |
|
||||
| **Auggie (Augment CLI)** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.augment/commands/`) |
|
||||
| **Claude Code** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` |
|
||||
| **Cline** | Workflows in `.clinerules/workflows/` directory (`.clinerules/workflows/openspec-*.md`) |
|
||||
| **CodeBuddy Code (CLI)** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.codebuddy/commands/`) — see [docs](https://www.codebuddy.ai/cli) |
|
||||
| **Codex** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (global: `~/.codex/prompts`, auto-installed) |
|
||||
| **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/`) |
|
||||
|
||||
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`.
|
||||
|
||||
</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 |
|
||||
|-------|
|
||||
| Amp • Jules • Others |
|
||||
|
||||
</details>
|
||||
|
||||
### Install & Initialize
|
||||
|
||||
#### Prerequisites
|
||||
- **Node.js >= 20.19.0** - Check your version with `node --version`
|
||||
|
||||
#### Step 1: Install the CLI globally
|
||||
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
```
|
||||
|
||||
Verify installation:
|
||||
```bash
|
||||
openspec --version
|
||||
```
|
||||
|
||||
#### Step 2: Initialize OpenSpec in your project
|
||||
|
||||
Navigate to your project directory:
|
||||
```bash
|
||||
cd my-project
|
||||
```
|
||||
|
||||
Run the initialization:
|
||||
```bash
|
||||
openspec init
|
||||
```
|
||||
|
||||
**What happens during initialization:**
|
||||
- You'll be prompted to pick any natively supported AI tools (Claude Code, CodeBuddy, Cursor, OpenCode, Qoder,etc.); other assistants always rely on the shared `AGENTS.md` stub
|
||||
- OpenSpec automatically configures slash commands for the tools you choose and always writes a managed `AGENTS.md` hand-off at the project root
|
||||
- A new `openspec/` directory structure is created in your project
|
||||
|
||||
**After setup:**
|
||||
- Primary AI tools can trigger `/openspec` workflows without additional configuration
|
||||
- Run `openspec list` to verify the setup and view any active changes
|
||||
- If your coding assistant doesn't surface the new slash commands right away, restart it. Slash commands are loaded at startup,
|
||||
so a fresh launch ensures they appear
|
||||
|
||||
### Optional: Populate Project Context
|
||||
|
||||
After `openspec init` completes, you'll receive a suggested prompt to help populate your project context:
|
||||
|
||||
```text
|
||||
Populate your project context:
|
||||
"Please read openspec/project.md and help me fill it out with details about my project, tech stack, and conventions"
|
||||
```
|
||||
|
||||
Use `openspec/project.md` to define project-level conventions, standards, architectural patterns, and other guidelines that should be followed across all changes.
|
||||
|
||||
### Create Your First Change
|
||||
|
||||
Here's a real example showing the complete OpenSpec workflow. This works with any AI tool. Those with native slash commands will recognize the shortcuts automatically.
|
||||
|
||||
#### 1. Draft the Proposal
|
||||
Start by asking your AI to create a change proposal:
|
||||
|
||||
```text
|
||||
You: Create an OpenSpec change proposal for adding profile search filters by role and team
|
||||
(Shortcut for tools with slash commands: /openspec:proposal Add profile search filters)
|
||||
|
||||
AI: I'll create an OpenSpec change proposal for profile filters.
|
||||
*Scaffolds openspec/changes/add-profile-filters/ with proposal.md, tasks.md, spec deltas.*
|
||||
```
|
||||
|
||||
#### 2. Verify & Review
|
||||
Check that the change was created correctly and review the proposal:
|
||||
|
||||
```bash
|
||||
$ openspec list # Confirm the change folder exists
|
||||
$ openspec validate add-profile-filters # Validate spec formatting
|
||||
$ openspec show add-profile-filters # Review proposal, tasks, and spec delta
|
||||
```
|
||||
|
||||
#### 3. Refine the Specs
|
||||
Iterate on the specifications until they match your needs:
|
||||
|
||||
```text
|
||||
You: Can you add acceptance criteria for the role and team filters?
|
||||
|
||||
AI: I'll update the spec delta with scenarios for role and team filters.
|
||||
*Edits openspec/changes/add-profile-filters/specs/profile/spec.md and tasks.md.*
|
||||
```
|
||||
|
||||
#### 4. Implement the Change
|
||||
Once specs look good, start implementation:
|
||||
|
||||
```text
|
||||
You: The specs look good. Let's implement this change.
|
||||
(Shortcut for tools with slash commands: /openspec:apply add-profile-filters)
|
||||
|
||||
AI: I'll work through the tasks in the add-profile-filters change.
|
||||
*Implements tasks from openspec/changes/add-profile-filters/tasks.md*
|
||||
*Marks tasks complete: Task 1.1 ✓, Task 1.2 ✓, Task 2.1 ✓...*
|
||||
```
|
||||
|
||||
#### 5. Archive the Completed Change
|
||||
After implementation is complete, archive the change:
|
||||
|
||||
```text
|
||||
AI: All tasks are complete. The implementation is ready.
|
||||
|
||||
You: Please archive the change
|
||||
(Shortcut for tools with slash commands: /openspec:archive add-profile-filters)
|
||||
|
||||
AI: I'll archive the add-profile-filters change.
|
||||
*Runs: openspec archive add-profile-filters --yes*
|
||||
✓ Change archived successfully. Specs updated. Ready for the next feature!
|
||||
```
|
||||
|
||||
Or run the command yourself in terminal:
|
||||
```bash
|
||||
$ openspec archive add-profile-filters --yes # Archive the completed change without prompts
|
||||
```
|
||||
|
||||
**Note:** Tools with native slash commands (Claude Code, CodeBuddy, Cursor, Codex, Qoder, RooCode) can use the shortcuts shown. All other tools work with natural language requests to "create an OpenSpec proposal", "apply the OpenSpec change", or "archive the change".
|
||||
|
||||
## Command Reference
|
||||
|
||||
```bash
|
||||
openspec list # View active change folders
|
||||
openspec view # Interactive dashboard of specs and changes
|
||||
openspec show <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)
|
||||
```
|
||||
|
||||
## Example: How AI Creates OpenSpec Files
|
||||
|
||||
When you ask your AI assistant to "add two-factor authentication", it creates:
|
||||
|
||||
```
|
||||
openspec/
|
||||
├── specs/
|
||||
│ └── auth/
|
||||
│ └── spec.md # Current auth spec (if exists)
|
||||
└── changes/
|
||||
└── add-2fa/ # AI creates this entire structure
|
||||
├── proposal.md # Why and what changes
|
||||
├── tasks.md # Implementation checklist
|
||||
├── design.md # Technical decisions (optional)
|
||||
└── specs/
|
||||
└── auth/
|
||||
└── spec.md # Delta showing additions
|
||||
```
|
||||
|
||||
### AI-Generated Spec (created in `openspec/specs/auth/spec.md`):
|
||||
|
||||
```markdown
|
||||
# Auth Specification
|
||||
|
||||
## Purpose
|
||||
Authentication and session management.
|
||||
|
||||
## Requirements
|
||||
### Requirement: User Authentication
|
||||
The system SHALL issue a JWT on successful login.
|
||||
|
||||
#### Scenario: Valid credentials
|
||||
- WHEN a user submits valid credentials
|
||||
- THEN a JWT is returned
|
||||
```
|
||||
|
||||
### AI-Generated Change Delta (created in `openspec/changes/add-2fa/specs/auth/spec.md`):
|
||||
|
||||
```markdown
|
||||
# Delta for Auth
|
||||
|
||||
## ADDED Requirements
|
||||
### Requirement: Two-Factor Authentication
|
||||
The system MUST require a second factor during login.
|
||||
|
||||
#### Scenario: OTP required
|
||||
- WHEN a user submits valid credentials
|
||||
- THEN an OTP challenge is required
|
||||
```
|
||||
|
||||
### AI-Generated Tasks (created in `openspec/changes/add-2fa/tasks.md`):
|
||||
|
||||
```markdown
|
||||
## 1. Database Setup
|
||||
- [ ] 1.1 Add OTP secret column to users table
|
||||
- [ ] 1.2 Create OTP verification logs table
|
||||
|
||||
## 2. Backend Implementation
|
||||
- [ ] 2.1 Add OTP generation endpoint
|
||||
- [ ] 2.2 Modify login flow to require OTP
|
||||
- [ ] 2.3 Add OTP verification endpoint
|
||||
|
||||
## 3. Frontend Updates
|
||||
- [ ] 3.1 Create OTP input component
|
||||
- [ ] 3.2 Update login flow UI
|
||||
```
|
||||
|
||||
**Important:** You don't create these files manually. Your AI assistant generates them based on your requirements and the existing codebase.
|
||||
|
||||
## Understanding OpenSpec Files
|
||||
|
||||
### Delta Format
|
||||
|
||||
Deltas are "patches" that show how specs change:
|
||||
|
||||
- **`## ADDED Requirements`** - New capabilities
|
||||
- **`## MODIFIED Requirements`** - Changed behavior (include complete updated text)
|
||||
- **`## REMOVED Requirements`** - Deprecated features
|
||||
|
||||
**Format requirements:**
|
||||
- Use `### Requirement: <name>` for headers
|
||||
- Every requirement needs at least one `#### Scenario:` block
|
||||
- Use SHALL/MUST in requirement text
|
||||
|
||||
## How OpenSpec Compares
|
||||
|
||||
### vs. spec-kit
|
||||
OpenSpec’s two-folder model (`openspec/specs/` for the current truth, `openspec/changes/` for proposed updates) keeps state and diffs separate. This scales when you modify existing features or touch multiple specs. spec-kit is strong for greenfield/0→1 but provides less structure for cross-spec updates and evolving features.
|
||||
|
||||
### vs. Kiro.dev
|
||||
OpenSpec groups every change for a feature in one folder (`openspec/changes/feature-name/`), making it easy to track related specs, tasks, and designs together. Kiro spreads updates across multiple spec folders, which can make feature tracking harder.
|
||||
|
||||
### vs. No Specs
|
||||
Without specs, AI coding assistants generate code from vague prompts, often missing requirements or adding unwanted features. OpenSpec brings predictability by agreeing on the desired behavior before any code is written.
|
||||
|
||||
## Team Adoption
|
||||
|
||||
1. **Initialize OpenSpec** – Run `openspec init` in your repo.
|
||||
2. **Start with new features** – Ask your AI to capture upcoming work as change proposals.
|
||||
3. **Grow incrementally** – Each change archives into living specs that document your system.
|
||||
4. **Stay flexible** – Different teammates can use Claude Code, CodeBuddy, Cursor, or any AGENTS.md-compatible tool while sharing the same specs.
|
||||
|
||||
Run `openspec update` whenever someone switches tools so your agents pick up the latest instructions and slash-command bindings.
|
||||
|
||||
## Updating OpenSpec
|
||||
|
||||
1. **Upgrade the package**
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
```
|
||||
2. **Refresh agent instructions**
|
||||
- Run `openspec update` inside each project to regenerate AI guidance and ensure the latest slash commands are active.
|
||||
|
||||
## Experimental Features
|
||||
|
||||
<details>
|
||||
<summary><strong>🧪 OPSX: Fluid, Iterative Workflow</strong> (Claude Code only)</summary>
|
||||
|
||||
**Why this exists:**
|
||||
- Standard workflow is locked down — you can't tweak instructions or customize
|
||||
- When AI output is bad, you can't improve the prompts yourself
|
||||
- Same workflow for everyone, no way to match how your team works
|
||||
|
||||
**What's different:**
|
||||
- **Hackable** — edit templates and schemas yourself, test immediately, no rebuild
|
||||
- **Granular** — each artifact has its own instructions, test and tweak individually
|
||||
- **Customizable** — define your own workflows, artifacts, and dependencies
|
||||
- **Fluid** — no phase gates, update any artifact anytime
|
||||
|
||||
```
|
||||
You can always go back:
|
||||
|
||||
proposal ──→ specs ──→ design ──→ tasks ──→ implement
|
||||
▲ ▲ ▲ │
|
||||
└───────────┴──────────┴────────────────────┘
|
||||
```
|
||||
|
||||
| Command | What it does |
|
||||
|---------|--------------|
|
||||
| `/opsx:new` | Start a new change |
|
||||
| `/opsx:continue` | Create the next artifact (based on what's ready) |
|
||||
| `/opsx:ff` | Fast-forward (all planning artifacts at once) |
|
||||
| `/opsx:apply` | Implement tasks, updating artifacts as needed |
|
||||
| `/opsx:archive` | Archive when done |
|
||||
|
||||
**Setup:** `openspec artifact-experimental-setup`
|
||||
|
||||
[Full documentation →](docs/experimental-workflow.md)
|
||||
|
||||
</details>
|
||||
|
||||
## Contributing
|
||||
|
||||
- Install dependencies: `pnpm install`
|
||||
- Build: `pnpm run build`
|
||||
- Test: `pnpm test`
|
||||
- Develop CLI locally: `pnpm run dev` or `pnpm run dev:cli`
|
||||
- Conventional commits (one-line): `type(scope): subject`
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 450 KiB |
@@ -0,0 +1,89 @@
|
||||
<svg width="640" height="80" viewBox="0 0 640 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M32 0H16V16H32V0Z" fill="white"/>
|
||||
<path d="M48 0H32V16H48V0Z" fill="white"/>
|
||||
<path d="M16 16H0V32H16V16Z" fill="white"/>
|
||||
<path d="M64 16H48V32H64V16Z" fill="white"/>
|
||||
<path d="M16 32H0V48H16V32Z" fill="white"/>
|
||||
<path d="M64 32H48V48H64V32Z" fill="white"/>
|
||||
<path d="M16 48H0V64H16V48Z" fill="white"/>
|
||||
<path d="M64 48H48V64H64V48Z" fill="white"/>
|
||||
<path d="M32 64H16V80H32V64Z" fill="white"/>
|
||||
<path d="M48 64H32V80H48V64Z" fill="white"/>
|
||||
<path d="M96 0H80V16H96V0Z" fill="white"/>
|
||||
<path d="M112 0H96V16H112V0Z" fill="white"/>
|
||||
<path d="M128 0H112V16H128V0Z" fill="white"/>
|
||||
<path d="M96 16H80V32H96V16Z" fill="white"/>
|
||||
<path d="M144 16H128V32H144V16Z" fill="white"/>
|
||||
<path d="M96 32H80V48H96V32Z" fill="white"/>
|
||||
<path d="M112 32H96V48H112V32Z" fill="white"/>
|
||||
<path d="M128 32H112V48H128V32Z" fill="white"/>
|
||||
<path d="M144 32H128V48H144V32Z" fill="white"/>
|
||||
<path d="M96 48H80V64H96V48Z" fill="white"/>
|
||||
<path d="M96 64H80V80H96V64Z" fill="white"/>
|
||||
<path d="M176 0H160V16H176V0Z" fill="white"/>
|
||||
<path d="M192 0H176V16H192V0Z" fill="white"/>
|
||||
<path d="M208 0H192V16H208V0Z" fill="white"/>
|
||||
<path d="M224 0H208V16H224V0Z" fill="white"/>
|
||||
<path d="M176 16H160V32H176V16Z" fill="white"/>
|
||||
<path d="M176 32H160V48H176V32Z" fill="white"/>
|
||||
<path d="M192 32H176V48H192V32Z" fill="white"/>
|
||||
<path d="M208 32H192V48H208V32Z" fill="white"/>
|
||||
<path d="M176 48H160V64H176V48Z" fill="white"/>
|
||||
<path d="M176 64H160V80H176V64Z" fill="white"/>
|
||||
<path d="M192 64H176V80H192V64Z" fill="white"/>
|
||||
<path d="M208 64H192V80H208V64Z" fill="white"/>
|
||||
<path d="M224 64H208V80H224V64Z" fill="white"/>
|
||||
<path d="M256 0H240V16H256V0Z" fill="white"/>
|
||||
<path d="M304 0H288V16H304V0Z" fill="white"/>
|
||||
<path d="M256 16H240V32H256V16Z" fill="white"/>
|
||||
<path d="M272 16H256V32H272V16Z" fill="white"/>
|
||||
<path d="M304 16H288V32H304V16Z" fill="white"/>
|
||||
<path d="M256 32H240V48H256V32Z" fill="white"/>
|
||||
<path d="M288 32H272V48H288V32Z" fill="white"/>
|
||||
<path d="M304 32H288V48H304V32Z" fill="white"/>
|
||||
<path d="M256 48H240V64H256V48Z" fill="white"/>
|
||||
<path d="M304 48H288V64H304V48Z" fill="white"/>
|
||||
<path d="M256 64H240V80H256V64Z" fill="white"/>
|
||||
<path d="M304 64H288V80H304V64Z" fill="white"/>
|
||||
<path d="M352 0H336V16H352V0Z" fill="white"/>
|
||||
<path d="M368 0H352V16H368V0Z" fill="white"/>
|
||||
<path d="M384 0H368V16H384V0Z" fill="white"/>
|
||||
<path d="M336 16H320V32H336V16Z" fill="white"/>
|
||||
<path d="M352 32H336V48H352V32Z" fill="white"/>
|
||||
<path d="M368 32H352V48H368V32Z" fill="white"/>
|
||||
<path d="M384 48H368V64H384V48Z" fill="white"/>
|
||||
<path d="M336 64H320V80H336V64Z" fill="white"/>
|
||||
<path d="M352 64H336V80H352V64Z" fill="white"/>
|
||||
<path d="M368 64H352V80H368V64Z" fill="white"/>
|
||||
<path d="M416 0H400V16H416V0Z" fill="white"/>
|
||||
<path d="M432 0H416V16H432V0Z" fill="white"/>
|
||||
<path d="M448 0H432V16H448V0Z" fill="white"/>
|
||||
<path d="M416 16H400V32H416V16Z" fill="white"/>
|
||||
<path d="M464 16H448V32H464V16Z" fill="white"/>
|
||||
<path d="M416 32H400V48H416V32Z" fill="white"/>
|
||||
<path d="M432 32H416V48H432V32Z" fill="white"/>
|
||||
<path d="M448 32H432V48H448V32Z" fill="white"/>
|
||||
<path d="M464 32H448V48H464V32Z" fill="white"/>
|
||||
<path d="M416 48H400V64H416V48Z" fill="white"/>
|
||||
<path d="M416 64H400V80H416V64Z" fill="white"/>
|
||||
<path d="M496 0H480V16H496V0Z" fill="white"/>
|
||||
<path d="M512 0H496V16H512V0Z" fill="white"/>
|
||||
<path d="M528 0H512V16H528V0Z" fill="white"/>
|
||||
<path d="M544 0H528V16H544V0Z" fill="white"/>
|
||||
<path d="M496 16H480V32H496V16Z" fill="white"/>
|
||||
<path d="M496 32H480V48H496V32Z" fill="white"/>
|
||||
<path d="M512 32H496V48H512V32Z" fill="white"/>
|
||||
<path d="M528 32H512V48H528V32Z" fill="white"/>
|
||||
<path d="M496 48H480V64H496V48Z" fill="white"/>
|
||||
<path d="M496 64H480V80H496V64Z" fill="white"/>
|
||||
<path d="M512 64H496V80H512V64Z" fill="white"/>
|
||||
<path d="M528 64H512V80H528V64Z" fill="white"/>
|
||||
<path d="M544 64H528V80H544V64Z" fill="white"/>
|
||||
<path d="M592 0H576V16H592V0Z" fill="white"/>
|
||||
<path d="M608 0H592V16H608V0Z" fill="white"/>
|
||||
<path d="M576 16H560V32H576V16Z" fill="white"/>
|
||||
<path d="M576 32H560V48H576V32Z" fill="white"/>
|
||||
<path d="M576 48H560V64H576V48Z" fill="white"/>
|
||||
<path d="M592 64H576V80H592V64Z" fill="white"/>
|
||||
<path d="M608 64H592V80H608V64Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -0,0 +1,89 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="80" viewBox="0 0 640 80">
|
||||
<rect x="16" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="32" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="0" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="48" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="0" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="48" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="0" y="48" width="16" height="16" fill="black" />
|
||||
<rect x="48" y="48" width="16" height="16" fill="black" />
|
||||
<rect x="16" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="32" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="80" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="96" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="112" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="80" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="128" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="80" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="96" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="112" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="128" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="80" y="48" width="16" height="16" fill="black" />
|
||||
<rect x="80" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="160" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="176" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="192" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="208" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="160" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="160" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="176" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="192" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="160" y="48" width="16" height="16" fill="black" />
|
||||
<rect x="160" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="176" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="192" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="208" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="240" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="288" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="240" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="256" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="288" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="240" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="272" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="288" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="240" y="48" width="16" height="16" fill="black" />
|
||||
<rect x="288" y="48" width="16" height="16" fill="black" />
|
||||
<rect x="240" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="288" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="336" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="352" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="368" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="320" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="336" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="352" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="368" y="48" width="16" height="16" fill="black" />
|
||||
<rect x="320" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="336" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="352" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="400" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="416" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="432" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="400" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="448" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="400" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="416" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="432" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="448" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="400" y="48" width="16" height="16" fill="black" />
|
||||
<rect x="400" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="480" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="496" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="512" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="528" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="480" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="480" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="496" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="512" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="480" y="48" width="16" height="16" fill="black" />
|
||||
<rect x="480" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="496" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="512" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="528" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="576" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="592" y="0" width="16" height="16" fill="black" />
|
||||
<rect x="560" y="16" width="16" height="16" fill="black" />
|
||||
<rect x="560" y="32" width="16" height="16" fill="black" />
|
||||
<rect x="560" y="48" width="16" height="16" fill="black" />
|
||||
<rect x="576" y="64" width="16" height="16" fill="black" />
|
||||
<rect x="592" y="64" width="16" height="16" fill="black" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
@@ -1,7 +1,15 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { execSync } from 'child_process';
|
||||
import { execFileSync } from 'child_process';
|
||||
import { existsSync, rmSync } from 'fs';
|
||||
import { createRequire } from 'module';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
const runTsc = (args = []) => {
|
||||
const tscPath = require.resolve('typescript/bin/tsc');
|
||||
execFileSync(process.execPath, [tscPath, ...args], { stdio: 'inherit' });
|
||||
};
|
||||
|
||||
console.log('🔨 Building OpenSpec...\n');
|
||||
|
||||
@@ -11,12 +19,13 @@ if (existsSync('dist')) {
|
||||
rmSync('dist', { recursive: true, force: true });
|
||||
}
|
||||
|
||||
// Run TypeScript compiler
|
||||
// Run TypeScript compiler (use local version explicitly)
|
||||
console.log('Compiling TypeScript...');
|
||||
try {
|
||||
execSync('tsc', { stdio: 'inherit' });
|
||||
runTsc(['--version']);
|
||||
runTsc();
|
||||
console.log('\n✅ Build completed successfully!');
|
||||
} catch (error) {
|
||||
console.error('\n❌ Build failed!');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,597 @@
|
||||
# POC-OpenSpec-Core Analysis
|
||||
|
||||
---
|
||||
|
||||
## Design Decisions & Terminology
|
||||
|
||||
### Philosophy: Not a Workflow System
|
||||
|
||||
This system is **not** a workflow engine. It's an **artifact tracker with dependency awareness**.
|
||||
|
||||
| What it's NOT | What it IS |
|
||||
|---------------|------------|
|
||||
| Linear step-by-step progression | Exploratory, iterative planning |
|
||||
| Bureaucratic checkpoints | Enablers that unlock possibilities |
|
||||
| "You must complete step 1 first" | "Here's what you could create now" |
|
||||
| Form-filling | Fluid document creation |
|
||||
|
||||
**Key insight:** Dependencies are *enablers*, not *gates*. You can't meaningfully write a design document if there's no proposal to design from - that's not bureaucracy, it's logic.
|
||||
|
||||
### Terminology
|
||||
|
||||
| Term | Definition | Example |
|
||||
|------|------------|---------|
|
||||
| **Change** | A unit of work being planned (feature, refactor, migration) | `openspec/changes/add-auth/` |
|
||||
| **Schema** | An artifact graph definition (what artifacts exist, their dependencies) | `spec-driven.yaml` |
|
||||
| **Artifact** | A node in the graph (a document to create) | `proposal`, `design`, `specs` |
|
||||
| **Template** | Instructions/guidance for creating an artifact | `templates/proposal.md` |
|
||||
|
||||
### Hierarchy
|
||||
|
||||
```
|
||||
Schema (defines) ──→ Artifacts (guided by) ──→ Templates
|
||||
```
|
||||
|
||||
- **Schema** = the artifact graph (what exists, dependencies)
|
||||
- **Artifact** = a document to produce
|
||||
- **Template** = instructions for creating that artifact
|
||||
|
||||
### Schema Variations
|
||||
|
||||
Schemas can vary across multiple dimensions:
|
||||
|
||||
| Dimension | Examples |
|
||||
|-----------|----------|
|
||||
| Philosophy | `spec-driven`, `tdd`, `prototype-first` |
|
||||
| Version | `v1`, `v2`, `v3` |
|
||||
| Language | `en`, `zh`, `es` |
|
||||
| Custom | `team-alpha`, `experimental` |
|
||||
|
||||
### Schema Resolution (XDG Standard)
|
||||
|
||||
Schemas follow the XDG Base Directory Specification with a 2-level resolution:
|
||||
|
||||
```
|
||||
1. ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml # Global user override
|
||||
2. <package>/schemas/<name>/schema.yaml # Built-in defaults
|
||||
```
|
||||
|
||||
**Platform-specific paths:**
|
||||
- Unix/macOS: `~/.local/share/openspec/schemas/`
|
||||
- Windows: `%LOCALAPPDATA%/openspec/schemas/`
|
||||
- All platforms: `$XDG_DATA_HOME/openspec/schemas/` (when set)
|
||||
|
||||
**Why XDG?**
|
||||
- Schemas are workflow definitions (data), not user preferences (config)
|
||||
- Built-ins baked into package, never auto-copied
|
||||
- Users customize by creating files in global data dir
|
||||
- Consistent with modern CLI tooling standards
|
||||
|
||||
### Template Inheritance (2 Levels Max)
|
||||
|
||||
Templates are co-located with schemas in a `templates/` subdirectory:
|
||||
|
||||
```
|
||||
1. ${XDG_DATA_HOME}/openspec/schemas/<schema>/templates/<artifact>.md # User override
|
||||
2. <package>/schemas/<schema>/templates/<artifact>.md # Built-in
|
||||
```
|
||||
|
||||
**Rules:**
|
||||
- User overrides take precedence over package built-ins
|
||||
- A CLI command shows resolved paths (no guessing)
|
||||
- No inheritance between schemas (copy if you need to diverge)
|
||||
- Templates are always co-located with their schema
|
||||
|
||||
**Why this matters:**
|
||||
- Avoids "where does this come from?" debugging
|
||||
- No implicit magic that works until it doesn't
|
||||
- Schema + templates form a cohesive unit
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This is an **artifact tracker with dependency awareness** that guides iterative development through a structured artifact pipeline. The core innovation is using the **filesystem as a database** - artifact completion is detected by file existence, making the system stateless and version-control friendly.
|
||||
|
||||
The system answers:
|
||||
- "What artifacts exist for this change?"
|
||||
- "What could I create next?" (not "what must I create")
|
||||
- "What's blocking X?" (informational, not prescriptive)
|
||||
|
||||
---
|
||||
|
||||
## Core Components
|
||||
|
||||
### 1. ArtifactGraph (Slice 1 - COMPLETE)
|
||||
|
||||
The dependency graph engine with XDG-compliant schema resolution.
|
||||
|
||||
| Responsibility | Approach |
|
||||
|----------------|----------|
|
||||
| Model artifacts as a DAG | Artifact with `requires: string[]` |
|
||||
| Track completion state | `Set<string>` for completed artifacts |
|
||||
| Calculate build order | Kahn's algorithm (topological sort) |
|
||||
| Find ready artifacts | Check if all dependencies are in `completed` set |
|
||||
| Resolve schemas | XDG global → package built-ins |
|
||||
|
||||
**Key Data Structures (Zod-validated):**
|
||||
|
||||
```typescript
|
||||
// Zod schemas define types + validation
|
||||
const ArtifactSchema = z.object({
|
||||
id: z.string().min(1),
|
||||
generates: z.string().min(1), // e.g., "proposal.md" or "specs/*.md"
|
||||
description: z.string(),
|
||||
template: z.string(), // path to template file
|
||||
requires: z.array(z.string()).default([]),
|
||||
});
|
||||
|
||||
const SchemaYamlSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
version: z.number().int().positive(),
|
||||
description: z.string().optional(),
|
||||
artifacts: z.array(ArtifactSchema).min(1),
|
||||
});
|
||||
|
||||
// Derived types
|
||||
type Artifact = z.infer<typeof ArtifactSchema>;
|
||||
type SchemaYaml = z.infer<typeof SchemaYamlSchema>;
|
||||
```
|
||||
|
||||
**Key Methods:**
|
||||
- `resolveSchema(name)` - Load schema with XDG fallback
|
||||
- `ArtifactGraph.fromSchema(schema)` - Build graph from schema
|
||||
- `detectState(graph, changeDir)` - Scan filesystem for completion
|
||||
- `getNextArtifacts(graph, completed)` - Find artifacts ready to create
|
||||
- `getBuildOrder(graph)` - Topological sort of all artifacts
|
||||
- `getBlocked(graph, completed)` - Artifacts with unmet dependencies
|
||||
|
||||
---
|
||||
|
||||
### 2. Change Utilities (Slice 2)
|
||||
|
||||
Simple utility functions for programmatic change creation. No class, no abstraction layer.
|
||||
|
||||
| Responsibility | Approach |
|
||||
|----------------|----------|
|
||||
| Create changes | Create dirs under `openspec/changes/<name>/` with README |
|
||||
| Name validation | Enforce kebab-case naming |
|
||||
|
||||
**Key Paths:**
|
||||
|
||||
```
|
||||
openspec/changes/<name>/ → Change instances with artifacts (project-level)
|
||||
```
|
||||
|
||||
**Key Functions** (`src/utils/change-utils.ts`):
|
||||
- `createChange(projectRoot, name, description?)` - Create new change directory + README
|
||||
- `validateChangeName(name)` - Validate kebab-case naming, returns `{ valid, error? }`
|
||||
|
||||
**Note:** Existing CLI commands (`ListCommand`, `ChangeCommand`) already handle listing, path resolution, and existence checks. No need to extract that logic - it works fine as-is.
|
||||
|
||||
---
|
||||
|
||||
### 3. InstructionLoader (Slice 3)
|
||||
|
||||
Template resolution and instruction enrichment.
|
||||
|
||||
| Responsibility | Approach |
|
||||
|----------------|----------|
|
||||
| Resolve templates | XDG 2-level fallback (schema-specific → shared → built-in) |
|
||||
| Build dynamic context | Gather dependency status, change info |
|
||||
| Enrich templates | Inject context into base templates |
|
||||
| Generate status reports | Formatted markdown with progress |
|
||||
|
||||
**Key Class - ChangeState:**
|
||||
|
||||
```
|
||||
ChangeState {
|
||||
changeName: string
|
||||
changeDir: string
|
||||
graph: ArtifactGraph
|
||||
completed: Set<string>
|
||||
|
||||
// Methods
|
||||
getNextSteps(): string[]
|
||||
getStatus(artifactId): ArtifactStatus
|
||||
isComplete(): boolean
|
||||
}
|
||||
```
|
||||
|
||||
**Key Functions:**
|
||||
- `getTemplatePath(artifactId, schemaName?)` - Resolve with 2-level fallback
|
||||
- `getEnrichedInstructions(artifactId, projectRoot, changeName?)` - Main entry point
|
||||
- `getChangeStatus(projectRoot, changeName?)` - Formatted status report
|
||||
|
||||
---
|
||||
|
||||
### 4. CLI (Slice 4)
|
||||
|
||||
User interface layer. **All commands are deterministic** - require explicit `--change` parameter.
|
||||
|
||||
| Command | Function | Status |
|
||||
|---------|----------|--------|
|
||||
| `status --change <id>` | Show change progress (artifact graph) | **NEW** |
|
||||
| `next --change <id>` | Show artifacts ready to create | **NEW** |
|
||||
| `instructions <artifact> --change <id>` | Get enriched instructions for artifact | **NEW** |
|
||||
| `list` | List all changes | EXISTS (`openspec change list`) |
|
||||
| `new <name>` | Create change | **NEW** (uses `createChange()`) |
|
||||
| `init` | Initialize structure | EXISTS (`openspec init`) |
|
||||
| `templates --change <id>` | Show resolved template paths | **NEW** |
|
||||
|
||||
**Note:** Commands that operate on a change require `--change`. Missing parameter → error with list of available changes. Agent infers the change from conversation and passes it explicitly.
|
||||
|
||||
**Existing CLI commands** (not part of this slice):
|
||||
- `openspec change list` / `openspec change show <id>` / `openspec change validate <id>`
|
||||
- `openspec list --changes` / `openspec list --specs`
|
||||
- `openspec view` (dashboard)
|
||||
- `openspec init` / `openspec archive <change>`
|
||||
|
||||
---
|
||||
|
||||
### 5. Claude Commands
|
||||
|
||||
Integration layer for Claude Code. **Operational commands only** - artifact creation via natural language.
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `/status` | Show change progress |
|
||||
| `/next` | Show what's ready to create |
|
||||
| `/run [artifact]` | Execute a specific step (power users) |
|
||||
| `/list` | List all changes |
|
||||
| `/new <name>` | Create a new change |
|
||||
| `/init` | Initialize structure |
|
||||
|
||||
**Artifact creation:** Users say "create the proposal" or "write the tests" in natural language. The agent:
|
||||
1. Infers change from conversation (confirms if uncertain)
|
||||
2. Infers artifact from request
|
||||
3. Calls CLI with explicit `--change` parameter
|
||||
4. Creates artifact following instructions
|
||||
|
||||
This works for ANY artifact in ANY schema - no new slash commands needed when schemas change.
|
||||
|
||||
**Note:** Legacy commands (`/openspec-proposal`, `/openspec-apply`, `/openspec-archive`) exist in the main project for backward compatibility but are separate from this architecture.
|
||||
|
||||
---
|
||||
|
||||
## Component Dependency Graph
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ PRESENTATION LAYER │
|
||||
│ ┌──────────────┐ ┌────────────────────┐ │
|
||||
│ │ CLI │ ←─shell exec───────│ Claude Commands │ │
|
||||
│ └──────┬───────┘ └────────────────────┘ │
|
||||
└─────────┼───────────────────────────────────────────────────┘
|
||||
│ imports
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ORCHESTRATION LAYER │
|
||||
│ ┌────────────────────┐ ┌──────────────────────────┐ │
|
||||
│ │ InstructionLoader │ │ change-utils (Slice 2) │ │
|
||||
│ │ (Slice 3) │ │ createChange() │ │
|
||||
│ └─────────┬──────────┘ │ validateChangeName() │ │
|
||||
│ │ └──────────────────────────┘ │
|
||||
└────────────┼────────────────────────────────────────────────┘
|
||||
│ uses
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ CORE LAYER │
|
||||
│ ┌──────────────────────────────────────────────────────┐ │
|
||||
│ │ ArtifactGraph (Slice 1) │ │
|
||||
│ │ │ │
|
||||
│ │ Schema Resolution (XDG) ──→ Graph ──→ State Detection│ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
▲
|
||||
│ reads from
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ PERSISTENCE LAYER │
|
||||
│ ┌──────────────────┐ ┌────────────────────────────────┐ │
|
||||
│ │ XDG Schemas │ │ Project Artifacts │ │
|
||||
│ │ ~/.local/share/ │ │ openspec/changes/<name>/ │ │
|
||||
│ │ openspec/ │ │ - proposal.md, design.md │ │
|
||||
│ │ schemas/ │ │ - specs/*.md, tasks.md │ │
|
||||
│ └──────────────────┘ └────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Design Patterns
|
||||
|
||||
### 1. Filesystem as Database
|
||||
|
||||
No SQLite, no JSON state files. The existence of `proposal.md` means proposal is complete.
|
||||
|
||||
```
|
||||
// State detection is just file existence checking
|
||||
if (exists(artifactPath)) {
|
||||
completed.add(artifactId)
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Deterministic CLI, Inferring Agent
|
||||
|
||||
**CLI layer:** Always deterministic - requires explicit `--change` parameter.
|
||||
|
||||
```
|
||||
openspec status --change add-auth # explicit, works
|
||||
openspec status # error: "No change specified"
|
||||
```
|
||||
|
||||
**Agent layer:** Infers from conversation, confirms if uncertain, passes explicit `--change`.
|
||||
|
||||
This separation means:
|
||||
- CLI is pure, testable, no state to corrupt
|
||||
- Agent handles all "smartness"
|
||||
- No config.yaml tracking of "active change"
|
||||
|
||||
### 3. XDG-Compliant Schema Resolution
|
||||
|
||||
```
|
||||
${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml # User override
|
||||
↓ (not found)
|
||||
<package>/schemas/<name>/schema.yaml # Built-in
|
||||
↓ (not found)
|
||||
Error (schema not found)
|
||||
```
|
||||
|
||||
### 4. Two-Level Template Fallback
|
||||
|
||||
```
|
||||
${XDG_DATA_HOME}/openspec/schemas/<schema>/templates/<artifact>.md # User override
|
||||
↓ (not found)
|
||||
<package>/schemas/<schema>/templates/<artifact>.md # Built-in
|
||||
↓ (not found)
|
||||
Error (no silent fallback to avoid confusion)
|
||||
```
|
||||
|
||||
### 5. Glob Pattern Support
|
||||
|
||||
`specs/*.md` allows multiple files to satisfy a single artifact:
|
||||
|
||||
```
|
||||
if (artifact.generates.includes("*")) {
|
||||
const parentDir = changeDir / patternParts[0]
|
||||
if (exists(parentDir) && hasFiles(parentDir)) {
|
||||
completed.add(artifactId)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Stateless State Detection
|
||||
|
||||
Every command re-scans the filesystem. No cached state to corrupt.
|
||||
|
||||
---
|
||||
|
||||
## Artifact Pipeline (Default Schema)
|
||||
|
||||
The default `spec-driven` schema:
|
||||
|
||||
```
|
||||
┌──────────┐
|
||||
│ proposal │ (no dependencies)
|
||||
└────┬─────┘
|
||||
│
|
||||
▼
|
||||
┌──────────┐
|
||||
│ specs │ (requires: proposal)
|
||||
└────┬─────┘
|
||||
│
|
||||
├──────────────┐
|
||||
▼ ▼
|
||||
┌──────────┐ ┌──────────┐
|
||||
│ design │ │ │
|
||||
│ │◄──┤ proposal │
|
||||
└────┬─────┘ └──────────┘
|
||||
│ (requires: proposal, specs)
|
||||
▼
|
||||
┌──────────┐
|
||||
│ tasks │ (requires: design)
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
Other schemas (TDD, prototype-first) would have different graphs.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Order
|
||||
|
||||
Structured as **vertical slices** - each slice is independently testable.
|
||||
|
||||
---
|
||||
|
||||
### Slice 1: "What's Ready?" (Core Query) ✅ COMPLETE
|
||||
|
||||
**Delivers:** Types + Graph + State Detection + Schema Resolution
|
||||
|
||||
**Implementation:** `src/core/artifact-graph/`
|
||||
- `types.ts` - Zod schemas and derived TypeScript types
|
||||
- `schema.ts` - YAML parsing with Zod validation
|
||||
- `graph.ts` - ArtifactGraph class with topological sort
|
||||
- `state.ts` - Filesystem-based state detection
|
||||
- `resolver.ts` - XDG-compliant schema resolution
|
||||
- `builtin-schemas.ts` - Package-bundled default schemas
|
||||
|
||||
**Key decisions made:**
|
||||
- Zod for schema validation (consistent with project)
|
||||
- XDG for global schema overrides
|
||||
- `Set<string>` for completion state (immutable, functional)
|
||||
- `inProgress` and `failed` states deferred (require external tracking)
|
||||
|
||||
---
|
||||
|
||||
### Slice 2: "Change Creation Utilities"
|
||||
|
||||
**Delivers:** Utility functions for programmatic change creation
|
||||
|
||||
**Scope:**
|
||||
- `createChange(projectRoot, name, description?)` → creates directory + README
|
||||
- `validateChangeName(name)` → kebab-case pattern enforcement
|
||||
|
||||
**Not in scope (already exists in CLI commands):**
|
||||
- `listChanges()` → exists in `ListCommand` and `ChangeCommand.getActiveChanges()`
|
||||
- `getChangePath()` → simple `path.join()` inline
|
||||
- `changeExists()` → simple `fs.access()` inline
|
||||
- `isInitialized()` → simple directory check inline
|
||||
|
||||
**Why simplified:** Extracting existing CLI logic into a class would require similar refactoring of `SpecCommand` for consistency. The existing code works fine (~15 lines each). Only truly new functionality is `createChange()` + name validation.
|
||||
|
||||
---
|
||||
|
||||
### Slice 3: "Get Instructions" (Enrichment)
|
||||
|
||||
**Delivers:** Template resolution + context injection
|
||||
|
||||
**Testable behaviors:**
|
||||
- Template fallback: schema-specific → shared → built-in → error
|
||||
- Context injection: completed deps show ✓, missing show ✗
|
||||
- Output path shown correctly based on change directory
|
||||
|
||||
---
|
||||
|
||||
### Slice 4: "CLI + Integration"
|
||||
|
||||
**Delivers:** New artifact graph commands (builds on existing CLI)
|
||||
|
||||
**New commands:**
|
||||
- `status --change <id>` - Show artifact completion state
|
||||
- `next --change <id>` - Show ready-to-create artifacts
|
||||
- `instructions <artifact> --change <id>` - Get enriched template
|
||||
- `templates --change <id>` - Show resolved paths
|
||||
- `new <name>` - Create change (wrapper for `createChange()`)
|
||||
|
||||
**Already exists (not in scope):**
|
||||
- `openspec change list/show/validate` - change management
|
||||
- `openspec list --changes/--specs` - listing
|
||||
- `openspec view` - dashboard
|
||||
- `openspec init` - initialization
|
||||
|
||||
**Testable behaviors:**
|
||||
- Each new command produces expected output
|
||||
- Commands compose correctly (status → next → instructions flow)
|
||||
- Error handling for missing changes, invalid artifacts, etc.
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
# Global (XDG paths - user overrides)
|
||||
~/.local/share/openspec/ # Unix/macOS ($XDG_DATA_HOME/openspec/)
|
||||
%LOCALAPPDATA%/openspec/ # Windows
|
||||
└── schemas/ # Schema overrides
|
||||
└── custom-workflow/ # User-defined schema directory
|
||||
├── schema.yaml # Schema definition
|
||||
└── templates/ # Co-located templates
|
||||
└── proposal.md
|
||||
|
||||
# Package (built-in defaults)
|
||||
<package>/
|
||||
└── schemas/ # Built-in schema definitions
|
||||
├── spec-driven/ # Default: proposal → specs → design → tasks
|
||||
│ ├── schema.yaml
|
||||
│ └── templates/
|
||||
│ ├── proposal.md
|
||||
│ ├── design.md
|
||||
│ ├── spec.md
|
||||
│ └── tasks.md
|
||||
└── tdd/ # TDD: tests → implementation → docs
|
||||
├── schema.yaml
|
||||
└── templates/
|
||||
├── test.md
|
||||
├── implementation.md
|
||||
├── spec.md
|
||||
└── docs.md
|
||||
|
||||
# Project (change instances)
|
||||
openspec/
|
||||
└── changes/ # Change instances
|
||||
├── add-auth/
|
||||
│ ├── README.md # Auto-generated on creation
|
||||
│ ├── proposal.md # Created artifacts
|
||||
│ ├── design.md
|
||||
│ └── specs/
|
||||
│ └── *.md
|
||||
├── refactor-db/
|
||||
│ └── ...
|
||||
└── archive/ # Completed changes
|
||||
└── 2025-01-01-add-auth/
|
||||
|
||||
.claude/
|
||||
├── settings.local.json # Permissions
|
||||
└── commands/ # Slash commands
|
||||
└── *.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schema YAML Format
|
||||
|
||||
```yaml
|
||||
# Built-in: <package>/schemas/spec-driven/schema.yaml
|
||||
# Or user override: ~/.local/share/openspec/schemas/spec-driven/schema.yaml
|
||||
name: spec-driven
|
||||
version: 1
|
||||
description: Specification-driven development
|
||||
|
||||
artifacts:
|
||||
- id: proposal
|
||||
generates: "proposal.md"
|
||||
description: "Create project proposal document"
|
||||
template: "proposal.md" # resolves from co-located templates/ directory
|
||||
requires: []
|
||||
|
||||
- id: specs
|
||||
generates: "specs/*.md" # glob pattern
|
||||
description: "Create technical specification documents"
|
||||
template: "specs.md"
|
||||
requires:
|
||||
- proposal
|
||||
|
||||
- id: design
|
||||
generates: "design.md"
|
||||
description: "Create design document"
|
||||
template: "design.md"
|
||||
requires:
|
||||
- proposal
|
||||
- specs
|
||||
|
||||
- id: tasks
|
||||
generates: "tasks.md"
|
||||
description: "Create tasks breakdown document"
|
||||
template: "tasks.md"
|
||||
requires:
|
||||
- design
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Layer | Component | Responsibility | Status |
|
||||
|-------|-----------|----------------|--------|
|
||||
| Core | ArtifactGraph | Pure dependency logic + XDG schema resolution | ✅ Slice 1 COMPLETE |
|
||||
| Utils | change-utils | Change creation + name validation only | Slice 2 (new functionality only) |
|
||||
| Core | InstructionLoader | Template resolution + enrichment | Slice 3 (all new) |
|
||||
| Presentation | CLI | New artifact graph commands | Slice 4 (new commands only) |
|
||||
| Integration | Claude Commands | AI assistant glue | Slice 4 |
|
||||
|
||||
**What already exists (not in this proposal):**
|
||||
- `getActiveChangeIds()` in `src/utils/item-discovery.ts` - list changes
|
||||
- `ChangeCommand.list/show/validate()` in `src/commands/change.ts`
|
||||
- `ListCommand.execute()` in `src/core/list.ts`
|
||||
- `ViewCommand.execute()` in `src/core/view.ts` - dashboard
|
||||
- `src/core/init.ts` - initialization
|
||||
- `src/core/archive.ts` - archiving
|
||||
|
||||
**Key Principles:**
|
||||
- **Filesystem IS the database** - stateless, version-control friendly
|
||||
- **Dependencies are enablers** - show what's possible, don't force order
|
||||
- **Deterministic CLI, inferring agent** - CLI requires explicit `--change`, agent infers from context
|
||||
- **XDG-compliant paths** - schemas and templates use standard user data directories
|
||||
- **2-level inheritance** - user override → package built-in (no deeper)
|
||||
- **Schemas are versioned** - support variations by philosophy, version, language
|
||||
@@ -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,540 @@
|
||||
# Experimental Workflow (OPSX)
|
||||
|
||||
> **Status:** Experimental. Things might break. Feedback welcome on [Discord](https://discord.gg/BYjPaKbqMt).
|
||||
>
|
||||
> **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 artifact-experimental-setup
|
||||
```
|
||||
|
||||
This creates skills in `.claude/skills/` that Claude Code auto-detects.
|
||||
|
||||
## 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.
|
||||
|
||||
### 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 your own workflow by adding a schema to `~/.local/share/openspec/schemas/`:
|
||||
|
||||
```
|
||||
~/.local/share/openspec/schemas/research-first/
|
||||
├── schema.yaml
|
||||
└── templates/
|
||||
├── research.md
|
||||
├── proposal.md
|
||||
└── tasks.md
|
||||
|
||||
schema.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
|
||||
|
||||
Run `openspec schemas` to see available schemas.
|
||||
|
||||
## 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/BYjPaKbqMt) or open an issue on [GitHub](https://github.com/Fission-AI/openspec/issues).
|
||||
@@ -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,378 @@
|
||||
# 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 (XDG) | 2-level: user override → package built-in |
|
||||
| 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 |
|
||||
|
||||
### What's Missing
|
||||
|
||||
| Component | Status |
|
||||
|-----------|--------|
|
||||
| Schema bound to change | Not stored — must pass `--schema` every time |
|
||||
| Project-local schemas | Not supported — can't version control with repo |
|
||||
| Schema management CLI | None — manual path discovery required |
|
||||
| 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 | Workaround |
|
||||
|-----|--------|------------|
|
||||
| Schema not bound to change | Wrong results, forgotten context | Remember to pass `--schema` |
|
||||
| No project-local schemas | Can't share via repo | Manual XDG setup per machine |
|
||||
| No schema management CLI | Manual path hunting | Know XDG + find npm package |
|
||||
| No project default schema | Must specify every time | Always pass `--schema` |
|
||||
| No init-time schema selection | Missed setup opportunity | Manual config |
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
|
||||
**Priority:** High
|
||||
**Solves:** Team sharing, version control, no XDG knowledge needed
|
||||
|
||||
**Scope:**
|
||||
- Add `./openspec/schemas/` to resolution order (first priority)
|
||||
- `openspec schema copy <name> [new-name]` creates in project by default
|
||||
- `--global` flag for user-level XDG directory
|
||||
- Teams can commit `openspec/schemas/` to repo
|
||||
|
||||
**Resolution order:**
|
||||
```
|
||||
1. ./openspec/schemas/<name>/ # Project-local (NEW)
|
||||
2. ~/.local/share/openspec/schemas/<name>/ # User global
|
||||
3. <npm-package>/schemas/<name>/ # Built-in
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Schema Management CLI
|
||||
|
||||
**Priority:** Medium
|
||||
**Solves:** Path discovery, scaffolding, debugging
|
||||
|
||||
**Commands:**
|
||||
```bash
|
||||
openspec schema list # Show available schemas with sources
|
||||
openspec schema which <name> # Show resolution path
|
||||
openspec schema copy <name> [to] # Copy for customization
|
||||
openspec schema diff <name> # Compare with built-in
|
||||
openspec schema reset <name> # Remove override
|
||||
openspec schema validate <name> # Validate schema.yaml structure
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 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 |
|
||||
@@ -0,0 +1,42 @@
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
files: ['src/**/*.ts'],
|
||||
extends: [...tseslint.configs.recommended],
|
||||
rules: {
|
||||
// Prevent static imports of @inquirer modules to avoid pre-commit hook hangs.
|
||||
// These modules have side effects that can keep the Node.js event loop alive
|
||||
// when stdin is piped. Use dynamic import() instead.
|
||||
// See: https://github.com/Fission-AI/OpenSpec/issues/367
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: [
|
||||
{
|
||||
group: ['@inquirer/*'],
|
||||
message:
|
||||
'Use dynamic import() for @inquirer modules to prevent pre-commit hook hangs. See #367.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
// Disable rules that need broader cleanup - focus on critical issues only
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'no-empty': 'off',
|
||||
'prefer-const': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
// init.ts is dynamically imported from cli/index.ts, so static @inquirer
|
||||
// imports there are safe - they won't be loaded at CLI startup
|
||||
files: ['src/core/init.ts'],
|
||||
rules: {
|
||||
'no-restricted-imports': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ['dist/**', 'node_modules/**', '*.js', '*.mjs'],
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,98 @@
|
||||
# OpenSpec Parallel Delta Remediation Plan
|
||||
|
||||
## Problem Summary
|
||||
- Active changes apply requirement-level replacements when archiving. When two changes touch the same requirement, the second archive overwrites the first and silently drops scenarios (e.g., Windsurf vs. Kilo Code slash command updates).
|
||||
- The archive workflow (`src/core/archive.ts:191` and `src/core/archive.ts:501`) rebuilds main specs by replacing entire requirement blocks with the content contained in the change delta. The delta format (`src/core/parsers/requirement-blocks.ts:113`) has no notion of base versions or scenario-level operations.
|
||||
- The tooling cannot detect divergence between the change author’s starting point and the live spec, so parallel development corrupts the source of truth without warning.
|
||||
|
||||
## Observed Failure Mode
|
||||
- Change A (`add-windsurf-workflows`) adds a Windsurf scenario under `Slash Command Configuration`.
|
||||
- Change B (`add-kilocode-workflows`) adds a Kilo Code scenario to the same requirement, starting from the pre-Windsurf spec.
|
||||
- After Change A archives, the main spec contains both scenarios.
|
||||
- When Change B archives, `buildUpdatedSpec` sees a `MODIFIED` block for `Slash Command Configuration` and replaces the requirement with the four-scenario variant shipped in that change. Because that file never learned about Windsurf, the Windsurf scenario disappears.
|
||||
- There is no warning, diff, or conflict indicator—the archive completes successfully, and the source-of-truth spec now omits a shipped scenario.
|
||||
|
||||
## Root Causes
|
||||
1. **Replace-only semantics.** `buildUpdatedSpec` performs hash-map substitution of requirement blocks and cannot merge or compare individual scenarios (`src/core/archive.ts:455`-`src/core/archive.ts:526`).
|
||||
2. **Missing base fingerprint.** Changes do not persist the requirement content they were authored against, so the archive step cannot tell if the live spec diverged.
|
||||
3. **Single-level granularity.** The delta language only understands requirements. Even if we introduced scenario-level parsing, we would still lose sibling edits without an accompanying merge strategy.
|
||||
4. **Lack of conflict UX.** The CLI never forces contributors to reconcile parallel updates. There is no equivalent of `git merge`, `git rebase`, or conflict markers.
|
||||
|
||||
## Design Objectives
|
||||
- Preserve every approved scenario regardless of archive order.
|
||||
- Detect and block speculative archives when the live spec diverges from the author’s base.
|
||||
- Provide a deterministic, reviewable conflict resolution flow that mirrors source-control best practices.
|
||||
- Keep the authoring experience ergonomic: deltas should remain human-editable markdown.
|
||||
- Support incremental adoption so existing repositories can roll forward without breaking active work.
|
||||
|
||||
## Proposed Fix: Layered Remediation
|
||||
|
||||
### Phase 0 – Stop the Bleeding (Detection & Guardrails)
|
||||
1. **Persist requirement fingerprints alongside each change.**
|
||||
- When scaffolding or validating a change, capture the current requirement body for every `MODIFIED`/`REMOVED`/`RENAMED` entry and write it to `changes/<id>/meta.json`.
|
||||
- Store a stable hash (e.g., SHA-256) of the base requirement content and the raw text itself for later merges.
|
||||
2. **Validate fingerprints during archive.**
|
||||
- Before `buildUpdatedSpec` mutates specs, recompute the requirement hash from the live spec.
|
||||
- If the hash differs from the stored base, abort and instruct the user to rebase. This makes the destructive path impossible.
|
||||
3. **Surface intent in CLI output.**
|
||||
- Show which requirements are stale, when they diverged, and which change last touched them.
|
||||
4. **Document interim manual mitigation.**
|
||||
- Update `openspec/AGENTS.md` and docs so contributors know to rerun `openspec change sync` (see Phase 1) whenever another change lands.
|
||||
|
||||
_Outcome:_ We prevent data loss immediately while we work on a richer merge story.
|
||||
|
||||
### Phase 1 – Add a Rebase Workflow (Author-Side Merge)
|
||||
1. **Introduce `openspec change sync <id>` (or `rebase`).**
|
||||
- Reads the stored base snapshot, the current spec, and the author’s delta.
|
||||
- Performs a 3-way merge per requirement. A naive diff3 on markdown lines is acceptable initially because we already operate on requirement-sized chunks.
|
||||
- If the merge is clean, rewrite the `MODIFIED` block with the merged text and refresh the stored fingerprint.
|
||||
- On conflict, write conflict markers inside the change delta (similar to Git) and require the author to hand-edit before re-running validation.
|
||||
2. **Enrich validator messages.**
|
||||
- `openspec validate` should flag unresolved conflict markers or fingerprint mismatches so errors appear early in the workflow.
|
||||
3. **Optional:** Offer a `--rewrite-scenarios` helper that merges bullet lists of scenarios to reduce manual editing noise.
|
||||
|
||||
_Outcome:_ Contributors can safely reconcile their work with the latest spec before archiving, restoring true parallel development.
|
||||
|
||||
### Phase 2 – Increase Delta Granularity
|
||||
1. **Extend the delta language with scenario-level directives.**
|
||||
- Allow `## MODIFIED Requirements` + `## ADDED Scenarios` / `## MODIFIED Scenarios` sections nested under the requirement header.
|
||||
- Backed by stable scenario identifiers (explicit IDs or generated hashes) stored in `meta.json`. This lets the system reason about individual scenarios.
|
||||
2. **Teach the parser to understand nested operations.**
|
||||
- Update `parseDeltaSpec` to emit scenario-level operations in addition to requirement blocks.
|
||||
- Update `buildUpdatedSpec` (or its replacement) to merge scenario lists, preserving order while inserting new entries in a deterministic fashion.
|
||||
3. **Automate migration.**
|
||||
- Provide a one-time command that inspects each existing spec, injects scenario IDs, and rewrites in-flight change deltas into the richer format.
|
||||
4. **Continue to rely on the Phase 1 rebase flow for conflicts when two changes edit the same scenario body or description.**
|
||||
|
||||
_Outcome:_ Most concurrent updates become commutative, drastically reducing the odds of human merges.
|
||||
|
||||
### Phase 3 – Structured Spec Graph (Long-Term)
|
||||
1. **Define stable requirement IDs.**
|
||||
- Embed `Requirement ID: <uuid>` markers in specs so renames and moves are trackable.
|
||||
- This enables future features like cross-capability references and better diff visualizations.
|
||||
2. **Model spec edits as operations over an AST.**
|
||||
- Build an intermediate representation (IR) for requirements/scenarios/metadata.
|
||||
- Use operational transforms or CRDT-like techniques to guarantee merge associativity.
|
||||
3. **Integrate with Git directly.**
|
||||
- Offer optional `openspec branch` scaffolding that aligns spec changes with Git branches, letting teams leverage Git’s conflict editor for the markdown IR.
|
||||
|
||||
_Outcome:_ OpenSpec graduates from replace-based updates to a resilient, intent-preserving spec management platform.
|
||||
|
||||
## Migration & Product Impacts
|
||||
- **Backfill metadata:** add hashes for all active changes and the current main specs during the initial rollout.
|
||||
- **CLI UX:** new commands (`change sync`, enhanced `archive`) require documentation, help text, and release notes.
|
||||
- **Docs & AGENTS updates:** reinforce the rebase workflow and explain conflict resolution to AI assistants.
|
||||
- **Testing:** introduce fixtures covering divergent requirement fingerprints and merge resolution logic.
|
||||
- **Telemetry (optional):** log fingerprint mismatches so we can see how often teams hit conflicts after the rollout.
|
||||
|
||||
## Open Questions / Risks
|
||||
- How should we order scenarios when multiple changes insert at different points? (Consider optional `position` metadata or deterministic alphabetical fallbacks.)
|
||||
- What is the graceful failure mode if contributors delete the `meta.json` file? (CLI should recreate fingerprints on demand.)
|
||||
- Do we need to support offline authors who cannot easily re-run the sync command before archiving? (Potential `--accept-outdated` escape hatch for emergencies.)
|
||||
- How will archived historical changes be handled? We may need a migration script to embed fingerprints retroactively so re-validation succeeds.
|
||||
|
||||
## Immediate Next Steps
|
||||
1. Prototype fingerprint capture during `openspec change validate` and block archive on mismatches.
|
||||
2. Ship `openspec change sync` with line-based diff3 merging and conflict markers.
|
||||
3. Update contributor docs and AI instructions to mandate running `sync` before archiving.
|
||||
4. Plan the scenario-level delta extension and migration path as a follow-up RFC.
|
||||
@@ -0,0 +1,454 @@
|
||||
# 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,447 +0,0 @@
|
||||
# OpenSpec Instructions
|
||||
|
||||
This document provides instructions for AI coding assistants on how to use OpenSpec conventions for spec-driven development. Follow these rules precisely when working on OpenSpec-enabled projects.
|
||||
|
||||
## Core Principle
|
||||
|
||||
OpenSpec is an AI-native system for change-driven development where:
|
||||
- **Specs** (`specs/`) reflect what IS currently built and deployed
|
||||
- **Changes** (`changes/`) contain proposals for what SHOULD be changed
|
||||
- **AI drives the process** - You generate proposals, humans review and approve
|
||||
- **Specs are living documentation** - Always kept in sync with deployed code
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
openspec/
|
||||
├── project.md # Project-specific context (tech stack, conventions)
|
||||
├── README.md # This file - OpenSpec instructions
|
||||
├── specs/ # Current truth - what IS built
|
||||
│ ├── [capability]/ # Single, focused capability
|
||||
│ │ ├── spec.md # WHAT the capability does and WHY
|
||||
│ │ └── design.md # HOW it's built (established patterns)
|
||||
│ └── ...
|
||||
├── changes/ # Proposed changes - what we're CHANGING
|
||||
│ ├── [change-name]/
|
||||
│ │ ├── proposal.md # Why, what, impact (consolidated)
|
||||
│ │ ├── tasks.md # Implementation checklist
|
||||
│ │ ├── design.md # Technical decisions (optional, for complex changes)
|
||||
│ │ └── specs/ # Future state of affected specs
|
||||
│ │ └── [capability]/
|
||||
│ │ └── spec.md # Clean markdown (no diff syntax)
|
||||
│ └── archive/ # Completed changes (dated)
|
||||
```
|
||||
|
||||
### Capability Organization
|
||||
|
||||
**Use capabilities, not features** - Each directory under `specs/` represents a single, focused responsibility:
|
||||
- **Verb-noun naming**: `user-auth`, `payment-capture`, `order-checkout`
|
||||
- **10-minute rule**: Each capability should be understandable in <10 minutes
|
||||
- **Single purpose**: If it needs "AND" to describe it, split it
|
||||
|
||||
Examples:
|
||||
```
|
||||
✅ GOOD: user-auth, user-sessions, payment-capture, payment-refunds
|
||||
❌ BAD: users, payments, core, misc
|
||||
```
|
||||
|
||||
## Key Behavioral Rules
|
||||
|
||||
### 1. Always Start by Reading
|
||||
|
||||
Before any task:
|
||||
1. **Read relevant specs** in `specs/[capability]/spec.md` to understand current state
|
||||
2. **Check pending changes** in `changes/` directory for potential conflicts
|
||||
3. **Read project.md** for project-specific conventions
|
||||
|
||||
### 2. When to Create Change Proposals
|
||||
|
||||
**ALWAYS create a change proposal for:**
|
||||
- New features or functionality
|
||||
- Breaking changes (API changes, schema updates)
|
||||
- Architecture changes or new patterns
|
||||
- Performance optimizations that change behavior
|
||||
- Security updates affecting auth/access patterns
|
||||
- Any change requiring multiple steps or affecting multiple systems
|
||||
|
||||
**SKIP proposals for:**
|
||||
- Bug fixes that restore intended behavior
|
||||
- Typos, formatting, or comment updates
|
||||
- Dependency updates (unless breaking)
|
||||
- Configuration or environment variable changes
|
||||
- Adding tests for existing behavior
|
||||
- Documentation fixes
|
||||
|
||||
### 3. Creating a Change Proposal
|
||||
|
||||
When a user requests a significant change:
|
||||
|
||||
```bash
|
||||
# 1. Create the change directory
|
||||
openspec/changes/[descriptive-name]/
|
||||
|
||||
# 2. Generate proposal.md with all context
|
||||
## Why
|
||||
[1-2 sentences on the problem/opportunity]
|
||||
|
||||
## What Changes
|
||||
[Bullet list of changes, including breaking changes]
|
||||
|
||||
## Impact
|
||||
- Affected specs: [list capabilities that will change]
|
||||
- Affected code: [list key files/systems]
|
||||
|
||||
# 3. Create future state specs for ALL affected capabilities
|
||||
# - Store complete spec files as they will exist after the change
|
||||
# - Use clean markdown without diff syntax (+/- prefixes)
|
||||
# - Include all formatting and structure of the final intended state
|
||||
specs/
|
||||
└── [capability]/
|
||||
└── spec.md
|
||||
|
||||
# 4. Create tasks.md with implementation steps
|
||||
## 1. [Task Group]
|
||||
- [ ] 1.1 [Specific task]
|
||||
- [ ] 1.2 [Specific task]
|
||||
|
||||
# 5. For complex changes, add design.md
|
||||
[Technical decisions and trade-offs]
|
||||
```
|
||||
|
||||
### 4. The Change Lifecycle
|
||||
|
||||
1. **Propose** → Create change directory with all documentation
|
||||
2. **Review** → User reviews and approves the proposal
|
||||
3. **Implement** → Follow the approved tasks.md (can be multiple PRs)
|
||||
4. **Deploy** → User confirms deployment
|
||||
5. **Update Specs** → Sync specs/ with new reality (IF the change affects system capabilities)
|
||||
6. **Archive** → Move to `changes/archive/YYYY-MM-DD-[name]/`
|
||||
|
||||
### 5. Implementing Changes
|
||||
|
||||
When implementing an approved change:
|
||||
1. Follow the tasks.md checklist exactly
|
||||
2. **Mark completed tasks** in tasks.md as you finish them (e.g., `- [x] 1.1 Task completed`)
|
||||
3. Ensure code matches the proposed behavior
|
||||
4. Update any affected tests
|
||||
5. **Keep change in `changes/` directory** - do NOT archive in implementation PR
|
||||
|
||||
**Multiple Implementation PRs:**
|
||||
- Changes can be implemented across multiple PRs
|
||||
- Each PR should update tasks.md to mark what was completed
|
||||
- Different developers can work on different task groups
|
||||
- Example: PR #1 completes tasks 1.1-1.3, PR #2 completes tasks 2.1-2.4
|
||||
|
||||
### 6. Updating Specs and Archiving After Deployment
|
||||
|
||||
**Create a separate PR after deployment** that:
|
||||
1. Moves change to `changes/archive/YYYY-MM-DD-[name]/`
|
||||
2. Updates relevant files in `specs/` to reflect new reality (if needed)
|
||||
3. If design.md exists, incorporates proven patterns into `specs/[capability]/design.md`
|
||||
|
||||
This ensures changes are only archived when truly complete and deployed.
|
||||
|
||||
### 7. Types of Changes That Don't Require Specs
|
||||
|
||||
Some changes only affect development infrastructure and don't need specs:
|
||||
- Initial project setup (package.json, tsconfig.json, etc.)
|
||||
- Development tooling changes (linters, formatters, build tools)
|
||||
- CI/CD configuration
|
||||
- Development dependencies
|
||||
|
||||
For these changes:
|
||||
1. Implement → Deploy → Mark tasks complete → Archive
|
||||
2. Skip the "Update Specs" step entirely
|
||||
|
||||
### What Deserves a Spec?
|
||||
|
||||
Ask yourself:
|
||||
- Is this a system capability that users or other systems interact with?
|
||||
- Does it have ongoing behavior that needs documentation?
|
||||
- Would a new developer need to understand this to work with the system?
|
||||
|
||||
If NO to all → No spec needed (likely just tooling/infrastructure)
|
||||
|
||||
## Understanding Specs vs Code
|
||||
|
||||
### Specs Document WHAT and WHY
|
||||
```markdown
|
||||
# Authentication Spec
|
||||
|
||||
Users SHALL authenticate with email and password.
|
||||
|
||||
WHEN credentials are valid THEN issue JWT token.
|
||||
WHEN credentials are invalid THEN return generic error.
|
||||
|
||||
WHY: Prevent user enumeration attacks.
|
||||
```
|
||||
|
||||
### Code Documents HOW
|
||||
```javascript
|
||||
// Implementation details
|
||||
const user = await db.users.findOne({ email });
|
||||
const valid = await bcrypt.compare(password, user.hashedPassword);
|
||||
```
|
||||
|
||||
**Key Distinction**: Specs capture intent, constraints, and decisions that aren't obvious from code.
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### New Feature Request
|
||||
```
|
||||
User: "Add password reset functionality"
|
||||
|
||||
You should:
|
||||
1. Read specs/user-auth/spec.md
|
||||
2. Check changes/ for pending auth changes
|
||||
3. Create changes/add-password-reset/ with proposal
|
||||
4. Wait for approval before implementing
|
||||
```
|
||||
|
||||
### Bug Fix
|
||||
```
|
||||
User: "Getting null pointer error when bio is empty"
|
||||
|
||||
You should:
|
||||
1. Check if spec says bios are optional
|
||||
2. If yes → Fix directly (it's a bug)
|
||||
3. If no → Create change proposal (it's a behavior change)
|
||||
```
|
||||
|
||||
### Infrastructure Setup
|
||||
```
|
||||
User: "Initialize TypeScript project"
|
||||
|
||||
You should:
|
||||
1. Create change proposal for TypeScript setup
|
||||
2. Implement configuration files (PR #1)
|
||||
3. Mark tasks complete in tasks.md
|
||||
4. After deployment, create separate PR to archive
|
||||
(no specs update needed - this is tooling, not a capability)
|
||||
```
|
||||
|
||||
## Summary Workflow
|
||||
|
||||
1. **Receive request** → Determine if it needs a change proposal
|
||||
2. **Read current state** → Check specs and pending changes
|
||||
3. **Create proposal** → Generate complete change documentation
|
||||
4. **Get approval** → User reviews the proposal
|
||||
5. **Implement** → Follow approved tasks, mark completed items in tasks.md
|
||||
6. **Deploy** → User deploys the implementation
|
||||
7. **Archive PR** → Create separate PR to:
|
||||
- Move change to archive
|
||||
- Update specs if needed
|
||||
- Mark change as complete
|
||||
|
||||
## PR Workflow Examples
|
||||
|
||||
### Single Developer, Simple Change
|
||||
```
|
||||
PR #1: Implementation
|
||||
- Implement all tasks
|
||||
- Update tasks.md marking items complete
|
||||
- Get merged and deployed
|
||||
|
||||
PR #2: Archive (after deployment)
|
||||
- Move changes/feature-x/ → changes/archive/2025-01-15-feature-x/
|
||||
- Update specs if needed
|
||||
```
|
||||
|
||||
### Multiple Developers, Complex Change
|
||||
```
|
||||
PR #1: Alice implements auth components
|
||||
- Complete tasks 1.1, 1.2, 1.3
|
||||
- Update tasks.md marking these complete
|
||||
|
||||
PR #2: Bob implements UI components
|
||||
- Complete tasks 2.1, 2.2
|
||||
- Update tasks.md marking these complete
|
||||
|
||||
PR #3: Alice fixes integration issues
|
||||
- Complete remaining task 1.4
|
||||
- Update tasks.md
|
||||
|
||||
[Deploy all changes]
|
||||
|
||||
PR #4: Archive
|
||||
- Move to archive with deployment date
|
||||
- Update specs to reflect new auth flow
|
||||
```
|
||||
|
||||
### Key Rules
|
||||
- **Never archive in implementation PRs** - changes aren't done until deployed
|
||||
- **Always update tasks.md** - shows accurate progress
|
||||
- **One archive PR per change** - clear completion boundary
|
||||
- **Archive PR includes spec updates** - keeps specs current
|
||||
|
||||
## Capability Organization Best Practices
|
||||
|
||||
### Naming Capabilities
|
||||
- Use **verb-noun** patterns: `user-auth`, `payment-capture`, `order-checkout`
|
||||
- Be specific: `payment-capture` not just `payments`
|
||||
- Keep flat: Avoid nesting capabilities within capabilities
|
||||
- Singular focus: If you need "AND" to describe it, split it
|
||||
|
||||
### When to Split Capabilities
|
||||
Split when you have:
|
||||
- Multiple unrelated API endpoints
|
||||
- Different user personas or actors
|
||||
- Separate deployment considerations
|
||||
- Independent evolution paths
|
||||
|
||||
#### Capability Boundary Guidelines
|
||||
- Would you import these separately? → Separate capabilities
|
||||
- Different deployment cadence? → Separate capabilities
|
||||
- Different teams own them? → Separate capabilities
|
||||
- Shared data models are OK, shared business logic means combine
|
||||
|
||||
Examples:
|
||||
- user-auth (login/logout) vs user-sessions (token management) → SEPARATE
|
||||
- payment-capture vs payment-refunds → SEPARATE (different workflows)
|
||||
- user-profile vs user-settings → COMBINE (same data model, same owner)
|
||||
|
||||
### Cross-Cutting Concerns
|
||||
For system-wide policies (rate limiting, error handling, security), document them in:
|
||||
- `project.md` for project-wide conventions
|
||||
- Within relevant capability specs where they apply
|
||||
- Or create a dedicated capability if complex enough (e.g., `api-rate-limiting/`)
|
||||
|
||||
### Examples of Well-Organized Capabilities
|
||||
```
|
||||
specs/
|
||||
├── user-auth/ # Login, logout, password reset
|
||||
├── user-sessions/ # Token management, refresh
|
||||
├── user-profile/ # Profile CRUD operations
|
||||
├── payment-capture/ # Processing payments
|
||||
├── payment-refunds/ # Handling refunds
|
||||
└── order-checkout/ # Checkout workflow
|
||||
```
|
||||
|
||||
For detailed guidance, see the [Capability Organization Guide](../docs/capability-organization.md).
|
||||
|
||||
## Common Scenarios and Clarifications
|
||||
|
||||
### Decision Ambiguity: Bug vs Behavior Change
|
||||
|
||||
When specs are missing or ambiguous:
|
||||
- If NO spec exists → Treat current code behavior as implicit spec, require proposal
|
||||
- If spec is VAGUE → Require proposal to clarify spec alongside fix
|
||||
- If code and spec DISAGREE → Spec is truth, code is buggy (fix without proposal)
|
||||
- If unsure → Default to creating a proposal (safer option)
|
||||
|
||||
Example:
|
||||
```
|
||||
User: "The API returns 404 for missing users but should return 400"
|
||||
AI: Is this a bug (spec says 400) or behavior change (spec says 404)?
|
||||
```
|
||||
|
||||
### When You Don't Know the Scope
|
||||
It's OK to explore first! Tell the user you need to investigate, then create an informed proposal.
|
||||
|
||||
### Exploration Phase (When Needed)
|
||||
|
||||
BEFORE creating proposal, you may need exploration when:
|
||||
- User request is vague or high-level
|
||||
- Multiple implementation approaches exist
|
||||
- Scope is unclear without seeing code
|
||||
|
||||
Exploration checklist:
|
||||
1. Tell user you need to explore first
|
||||
2. Use Grep/Read to understand current state
|
||||
3. Create initial proposal based on findings
|
||||
4. Refine with user feedback
|
||||
|
||||
Example:
|
||||
```
|
||||
User: "Add caching to improve performance"
|
||||
AI: "Let me explore the codebase to understand the current architecture and identify caching opportunities."
|
||||
[After exploration]
|
||||
AI: "Based on my analysis, I've identified three areas where caching would help. Here's my proposal..."
|
||||
```
|
||||
|
||||
### When No Specs Exist
|
||||
Treat current code as implicit spec. Your proposal should document current state AND proposed changes.
|
||||
|
||||
### When in Doubt
|
||||
Default to creating a proposal. It's easier to skip an unnecessary proposal than fix an undocumented change.
|
||||
|
||||
### AI Workflow Adaptations
|
||||
|
||||
Task tracking with OpenSpec:
|
||||
- Track exploration tasks separately from implementation
|
||||
- Document proposal creation steps as you go
|
||||
- Keep implementation tasks separate until proposal approved
|
||||
|
||||
Parallel operations encouraged:
|
||||
- Read multiple specs simultaneously
|
||||
- Check multiple pending changes at once
|
||||
- Batch related searches for efficiency
|
||||
|
||||
Progress communication:
|
||||
- "Exploring codebase to understand scope..."
|
||||
- "Creating proposal based on findings..."
|
||||
- "Implementing approved changes..."
|
||||
|
||||
### For AI Assistants
|
||||
- Use your exploration tools liberally before proposing
|
||||
- Batch operations for efficiency
|
||||
- Communicate your progress
|
||||
- It's OK to revise proposals based on discoveries
|
||||
|
||||
## Edge Case Handling
|
||||
|
||||
### Multi-Capability Changes
|
||||
Create ONE proposal that:
|
||||
- Lists all affected capabilities
|
||||
- Shows changes per capability
|
||||
- Has unified task list
|
||||
- Gets approved as a whole
|
||||
|
||||
### Outdated Specs
|
||||
If specs clearly outdated:
|
||||
1. Create proposal to update specs to match reality
|
||||
2. Implement new feature in separate proposal
|
||||
3. OR combine both in one proposal with clear sections
|
||||
|
||||
### Emergency Hotfixes
|
||||
For critical production issues:
|
||||
1. Announce: "This is an emergency fix"
|
||||
2. Implement fix immediately
|
||||
3. Create retroactive proposal
|
||||
4. Update specs after deployment
|
||||
5. Tag with [EMERGENCY] in archive
|
||||
|
||||
### Pure Refactoring
|
||||
No proposal needed for:
|
||||
- Code formatting/style
|
||||
- Internal refactoring (same API)
|
||||
- Performance optimization (same behavior)
|
||||
- Adding types to untyped code
|
||||
|
||||
Proposal REQUIRED for:
|
||||
- API changes (even if compatible)
|
||||
- Database schema changes
|
||||
- Architecture changes
|
||||
- New dependencies
|
||||
|
||||
### Observability Additions
|
||||
No proposal needed for:
|
||||
- Adding log statements
|
||||
- New metrics/traces
|
||||
- Debugging additions
|
||||
- Error tracking
|
||||
|
||||
Proposal REQUIRED if:
|
||||
- Changes log format/structure
|
||||
- Adds new monitoring service
|
||||
- Changes what's logged (privacy)
|
||||
|
||||
## Remember
|
||||
|
||||
- You are the process driver - automate documentation burden
|
||||
- Specs must always reflect deployed reality
|
||||
- Changes are proposed, not imposed
|
||||
- Impact analysis prevents surprises
|
||||
- The simplicity is the power - just markdown files
|
||||
|
||||
By following these conventions, you enable true spec-driven development where documentation stays current, changes are traceable, and evolution is intentional.
|
||||
@@ -0,0 +1,68 @@
|
||||
# Implementation Order and Dependencies
|
||||
|
||||
## Required Implementation Sequence
|
||||
|
||||
The following changes must be implemented in this specific order due to dependencies:
|
||||
|
||||
### Phase 1: Foundation
|
||||
**1. add-zod-validation** (No dependencies)
|
||||
- Creates all core schemas (RequirementSchema, ScenarioSchema, SpecSchema, ChangeSchema, DeltaSchema)
|
||||
- Implements markdown parser utilities
|
||||
- Implements validation infrastructure and rules
|
||||
- Establishes validation patterns used by all commands
|
||||
- Must be completed first
|
||||
|
||||
### Phase 2: Change Commands
|
||||
**2. add-change-commands** (Depends on: add-zod-validation)
|
||||
- Imports ChangeSchema and DeltaSchema from zod validation
|
||||
- Reuses markdown parsing utilities
|
||||
- Implements change command with built-in validation
|
||||
- Uses validation infrastructure for change validate subcommand
|
||||
- Cannot start until schemas and validation exist
|
||||
|
||||
### Phase 3: Spec Commands
|
||||
**3. add-spec-commands** (Depends on: add-zod-validation, add-change-commands)
|
||||
- Imports RequirementSchema, ScenarioSchema, SpecSchema from zod validation
|
||||
- Reuses markdown parsing utilities
|
||||
- Implements spec command with built-in validation
|
||||
- Uses validation infrastructure for spec validate subcommand
|
||||
- Builds on patterns established by change commands
|
||||
|
||||
## Dependency Graph
|
||||
```
|
||||
add-zod-validation
|
||||
↓
|
||||
add-change-commands
|
||||
↓
|
||||
add-spec-commands
|
||||
```
|
||||
|
||||
## Key Dependencies
|
||||
|
||||
### Shared Code Dependencies
|
||||
1. **Schemas**: All schemas created in add-zod-validation, used by both command implementations
|
||||
2. **Validation**: Infrastructure created in add-zod-validation, integrated into both commands
|
||||
3. **Parsers**: Markdown parsing utilities created in add-zod-validation, used by both commands
|
||||
|
||||
### File Dependencies
|
||||
- `src/core/schemas/*.schema.ts` (created by add-zod-validation) → imported by both commands
|
||||
- `src/core/validation/validator.ts` (created by add-zod-validation) → used by both commands
|
||||
- `src/core/parsers/markdown-parser.ts` (created by add-zod-validation) → used by both commands
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### For Developers
|
||||
1. Complete each phase fully before moving to the next
|
||||
2. Run tests after each phase to ensure stability
|
||||
3. The legacy `list` command remains functional throughout
|
||||
|
||||
### For CI/CD
|
||||
1. Each change can be validated independently
|
||||
2. Integration tests should run after each phase
|
||||
3. Full system tests required after Phase 3
|
||||
|
||||
### Parallel Work Opportunities
|
||||
Within each phase, the following can be done in parallel:
|
||||
- **Phase 1**: Schema design, validation rules, and parser implementation
|
||||
- **Phase 2**: Change command features and legacy compatibility work
|
||||
- **Phase 3**: Spec command features and final integration
|
||||
@@ -1,9 +0,0 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. Update OpenSpec README
|
||||
- [ ] 1.1 Add "Start Simple" section after Core Principle
|
||||
- [ ] 1.2 Add complexity triggers to "When to Create Change Proposals" section
|
||||
- [ ] 1.3 Update AI workflow guidance to emphasize minimal implementations
|
||||
|
||||
## 2. Update CLAUDE.md
|
||||
- [ ] 2.1 Add complexity management rules to project instructions
|
||||
@@ -1,19 +0,0 @@
|
||||
# Add Status Command to OpenSpec CLI
|
||||
|
||||
## Why
|
||||
|
||||
Developers need to know which changes have all tasks completed and are ready to archive.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add `openspec status` command that scans the changes/ directory
|
||||
- Parse each tasks.md file to count `[x]` (complete) and `[ ]` (incomplete) tasks
|
||||
- Display each change with its completion status (e.g., "auth-feature: 5/5" or "auth-feature: ✓")
|
||||
- Skip the archive/ subdirectory
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: New capability `cli-status` will be added
|
||||
- Affected code:
|
||||
- `src/cli/index.ts` - Add status command
|
||||
- `src/core/status.ts` - New file with simple scanning and parsing logic (~50 lines)
|
||||
@@ -1,58 +0,0 @@
|
||||
# CLI Status Command Specification
|
||||
|
||||
## Purpose
|
||||
|
||||
The status command shows which OpenSpec changes are ready to archive by displaying task completion status for each change.
|
||||
|
||||
## Command Interface
|
||||
|
||||
```bash
|
||||
# Show status of all changes
|
||||
openspec status
|
||||
```
|
||||
|
||||
## Behavior
|
||||
|
||||
WHEN the status command runs:
|
||||
1. Scan the `openspec/changes/` directory
|
||||
2. Skip the `archive/` subdirectory
|
||||
3. For each change directory with a `tasks.md` file:
|
||||
- Count tasks marked with `[x]` (case-insensitive)
|
||||
- Count tasks marked with `[ ]`
|
||||
- Display the change name and completion status
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
add-auth-feature: 15/15
|
||||
fix-payment-bug: 8/8
|
||||
refactor-api: 3/10
|
||||
update-docs: 0/5
|
||||
```
|
||||
|
||||
Or with checkmark for fully complete:
|
||||
|
||||
```
|
||||
add-auth-feature: ✓
|
||||
fix-payment-bug: ✓
|
||||
refactor-api: 3/10
|
||||
update-docs: 0/5
|
||||
```
|
||||
|
||||
## Task Detection
|
||||
|
||||
The command recognizes these patterns as tasks:
|
||||
- `- [ ]` Incomplete task
|
||||
- `- [x]` Complete task (lowercase)
|
||||
- `- [X]` Complete task (uppercase)
|
||||
|
||||
## Error Handling
|
||||
|
||||
- If no `tasks.md` exists, skip that change
|
||||
- If `tasks.md` is empty or has no tasks, skip that change
|
||||
- Continue scanning even if individual files have errors
|
||||
|
||||
## Exit Codes
|
||||
|
||||
- `0`: Success - status displayed
|
||||
- `1`: Error - unable to scan changes directory
|
||||
@@ -1,8 +0,0 @@
|
||||
# Implementation Tasks for Status Command
|
||||
|
||||
## Core Implementation
|
||||
- [ ] Add status command to `src/cli/index.ts`
|
||||
- [ ] Create `src/core/status.ts` with directory scanning logic
|
||||
- [ ] Parse tasks.md files to count `[x]` and `[ ]` patterns
|
||||
- [ ] Display each change with completion status (name: complete/total)
|
||||
- [ ] Skip the archive/ subdirectory when scanning
|
||||
@@ -1,20 +0,0 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. Update Command Implementation
|
||||
- [ ] 1.1 Create `src/core/update.ts` with `UpdateCommand` class
|
||||
- [ ] 1.2 Check if `openspec` directory exists (use `FileSystemUtils.directoryExists`)
|
||||
- [ ] 1.3 Write `readmeTemplate` to `openspec/README.md` using `FileSystemUtils.writeFile`
|
||||
- [ ] 1.4 Update `CLAUDE.md` using markers via `FileSystemUtils.updateFileWithMarkers` and `TemplateManager.getClaudeTemplate()`
|
||||
- [ ] 1.5 Display ASCII-safe success message: `Updated OpenSpec instructions`
|
||||
|
||||
## 2. CLI Integration
|
||||
- [ ] 2.1 Register `update` command in `src/cli/index.ts`
|
||||
- [ ] 2.2 Add command description: `Update OpenSpec instruction files`
|
||||
- [ ] 2.3 Handle errors with `ora().fail(...)` and exit code 1 (missing `openspec` directory, file write errors)
|
||||
|
||||
## 3. Testing
|
||||
- [ ] 3.1 Verify `openspec/README.md` is fully replaced with latest template
|
||||
- [ ] 3.2 Verify `CLAUDE.md` OpenSpec block updates without altering user content outside markers
|
||||
- [ ] 3.3 Verify idempotency (running twice yields identical files, no duplicate markers)
|
||||
- [ ] 3.4 Verify error when `openspec` directory is missing with friendly message
|
||||
- [ ] 3.5 Verify success message displays properly in ASCII-only terminals
|
||||
@@ -0,0 +1,20 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. Update Command Implementation
|
||||
- [x] 1.1 Create `src/core/update.ts` with `UpdateCommand` class
|
||||
- [x] 1.2 Check if `openspec` directory exists (use `FileSystemUtils.directoryExists`)
|
||||
- [x] 1.3 Write `readmeTemplate` to `openspec/README.md` using `FileSystemUtils.writeFile`
|
||||
- [x] 1.4 Update `CLAUDE.md` using markers via `FileSystemUtils.updateFileWithMarkers` and `TemplateManager.getClaudeTemplate()`
|
||||
- [x] 1.5 Display ASCII-safe success message: `Updated OpenSpec instructions`
|
||||
|
||||
## 2. CLI Integration
|
||||
- [x] 2.1 Register `update` command in `src/cli/index.ts`
|
||||
- [x] 2.2 Add command description: `Update OpenSpec instruction files`
|
||||
- [x] 2.3 Handle errors with `ora().fail(...)` and exit code 1 (missing `openspec` directory, file write errors)
|
||||
|
||||
## 3. Testing
|
||||
- [x] 3.1 Verify `openspec/README.md` is fully replaced with latest template
|
||||
- [x] 3.2 Verify `CLAUDE.md` OpenSpec block updates without altering user content outside markers
|
||||
- [x] 3.3 Verify idempotency (running twice yields identical files, no duplicate markers)
|
||||
- [x] 3.4 Verify error when `openspec` directory is missing with friendly message
|
||||
- [x] 3.5 Verify success message displays properly in ASCII-only terminals
|
||||
@@ -0,0 +1,20 @@
|
||||
# Add List Command to OpenSpec CLI
|
||||
|
||||
## Why
|
||||
|
||||
Developers need visibility into available changes and their status to understand the project's evolution and pending work.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add `openspec list` command that displays all changes in the changes/ directory
|
||||
- Show each change name with task completion count (e.g., "add-auth: 3/5 tasks")
|
||||
- Display completion status indicator (✓ for fully complete, progress for partial)
|
||||
- Skip the archive/ subdirectory to focus on active changes
|
||||
- Simple table output for easy scanning
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: New capability `cli-list` will be added
|
||||
- Affected code:
|
||||
- `src/cli/index.ts` - Add list command
|
||||
- `src/core/list.ts` - New file with directory scanning and task parsing (~60 lines)
|
||||
@@ -0,0 +1,69 @@
|
||||
# List Command Specification
|
||||
|
||||
## Purpose
|
||||
|
||||
The `openspec list` command SHALL provide developers with a quick overview of all active changes in the project, showing their names and task completion status.
|
||||
|
||||
## Behavior
|
||||
|
||||
### Command Execution
|
||||
|
||||
WHEN `openspec list` is executed
|
||||
THEN scan the `openspec/changes/` directory for change directories
|
||||
AND exclude the `archive/` subdirectory from results
|
||||
AND parse each change's `tasks.md` file to count task completion
|
||||
|
||||
### Task Counting
|
||||
|
||||
WHEN parsing a `tasks.md` file
|
||||
THEN count tasks matching these patterns:
|
||||
- Completed: Lines containing `- [x]`
|
||||
- Incomplete: Lines containing `- [ ]`
|
||||
AND calculate total tasks as the sum of completed and incomplete
|
||||
|
||||
### Output Format
|
||||
|
||||
WHEN displaying the list
|
||||
THEN show a table with columns:
|
||||
- Change name (directory name)
|
||||
- Task progress (e.g., "3/5 tasks" or "✓ Complete")
|
||||
- Status indicator:
|
||||
- `✓` for fully completed changes (all tasks done)
|
||||
- Progress fraction for partial completion
|
||||
|
||||
Example output:
|
||||
```
|
||||
Changes:
|
||||
add-auth-feature 3/5 tasks
|
||||
update-api-docs ✓ Complete
|
||||
fix-validation 0/2 tasks
|
||||
add-list-command 1/4 tasks
|
||||
```
|
||||
|
||||
### Empty State
|
||||
|
||||
WHEN no active changes exist (only archive/ or empty changes/)
|
||||
THEN display: "No active changes found."
|
||||
|
||||
### Error Handling
|
||||
|
||||
IF a change directory has no `tasks.md` file
|
||||
THEN display the change with "No tasks" status
|
||||
|
||||
IF `openspec/changes/` directory doesn't exist
|
||||
THEN display error: "No OpenSpec changes directory found. Run 'openspec init' first."
|
||||
AND exit with code 1
|
||||
|
||||
### Sorting
|
||||
|
||||
Changes SHALL be displayed in alphabetical order by change name for consistency.
|
||||
|
||||
## Why
|
||||
|
||||
Developers need a quick way to:
|
||||
- See what changes are in progress
|
||||
- Identify which changes are ready to archive
|
||||
- Understand the overall project evolution status
|
||||
- Get a bird's-eye view without opening multiple files
|
||||
|
||||
This command provides that visibility with minimal effort, following OpenSpec's philosophy of simplicity and clarity.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. Core Implementation
|
||||
- [x] 1.1 Create `src/core/list.ts` with list logic
|
||||
- [x] 1.1.1 Implement directory scanning (exclude archive/)
|
||||
- [x] 1.1.2 Implement task counting from tasks.md files
|
||||
- [x] 1.1.3 Format output as simple table
|
||||
- [x] 1.2 Add list command to CLI in `src/cli/index.ts`
|
||||
- [x] 1.2.1 Register `openspec list` command
|
||||
- [x] 1.2.2 Connect to list.ts implementation
|
||||
|
||||
## 2. Error Handling
|
||||
- [x] 2.1 Handle missing openspec/changes/ directory
|
||||
- [x] 2.2 Handle changes without tasks.md files
|
||||
- [x] 2.3 Handle empty changes directory
|
||||
|
||||
## 3. Testing
|
||||
- [x] 3.1 Add tests for list functionality
|
||||
- [x] 3.1.1 Test with multiple changes
|
||||
- [x] 3.1.2 Test with completed changes
|
||||
- [x] 3.1.3 Test with no changes
|
||||
- [x] 3.1.4 Test error conditions
|
||||
|
||||
## 4. Documentation
|
||||
- [x] 4.1 Update CLI help text with list command
|
||||
- [x] 4.2 Add list command to README if applicable
|
||||
@@ -0,0 +1,9 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. Update OpenSpec README
|
||||
- [x] 1.1 Add "Start Simple" section after Core Principle
|
||||
- [x] 1.2 Add complexity triggers to "When to Create Change Proposals" section
|
||||
- [x] 1.3 Update AI workflow guidance to emphasize minimal implementations
|
||||
|
||||
## 2. Update CLAUDE.md
|
||||
- [x] 2.1 Add complexity management rules to project instructions
|
||||
@@ -0,0 +1,15 @@
|
||||
## Why
|
||||
Need a command to archive completed changes to the archive folder with proper date prefixing, following OpenSpec conventions. Currently changes must be manually moved and renamed.
|
||||
|
||||
## What Changes
|
||||
- Add new `archive` command to CLI that moves changes to `changes/archive/YYYY-MM-DD-[change-name]/`
|
||||
- Check for incomplete tasks before archiving and warn user
|
||||
- Allow interactive selection of change to archive
|
||||
- Prevent archiving if target directory already exists
|
||||
- Update main specs from the change's future state specs (copy from `changes/[name]/specs/` to `openspec/specs/`)
|
||||
- Show confirmation prompt before updating specs, displaying which specs will be created/updated
|
||||
- Support `--yes` flag to skip confirmations for automation
|
||||
|
||||
## Impact
|
||||
- Affected specs: cli-archive (new)
|
||||
- Affected code: src/cli/index.ts, src/core/archive.ts (new)
|
||||
@@ -0,0 +1,111 @@
|
||||
# CLI Archive Command Specification
|
||||
|
||||
## Purpose
|
||||
The archive command moves completed changes from the active changes directory to the archive folder with date-based naming, following OpenSpec conventions.
|
||||
|
||||
## Command Syntax
|
||||
```bash
|
||||
openspec archive [change-name] [--yes|-y]
|
||||
```
|
||||
|
||||
Options:
|
||||
- `--yes`, `-y`: Skip confirmation prompts (for automation)
|
||||
|
||||
## Behavior
|
||||
|
||||
### Change Selection
|
||||
WHEN no change-name is provided
|
||||
THEN display interactive list of available changes (excluding archive/)
|
||||
AND allow user to select one
|
||||
|
||||
WHEN change-name is provided
|
||||
THEN use that change directly
|
||||
AND validate it exists
|
||||
|
||||
### Task Completion Check
|
||||
The command SHALL scan the change's tasks.md file for incomplete tasks (marked with `- [ ]`)
|
||||
|
||||
WHEN incomplete tasks are found
|
||||
THEN display all incomplete tasks to the user
|
||||
AND prompt for confirmation to continue
|
||||
AND default to "No" for safety
|
||||
|
||||
WHEN all tasks are complete OR no tasks.md exists
|
||||
THEN proceed with archiving without prompting
|
||||
|
||||
### Archive Process
|
||||
The archive operation SHALL:
|
||||
1. Create archive/ directory if it doesn't exist
|
||||
2. Generate target name as `YYYY-MM-DD-[change-name]` using current date
|
||||
3. Check if target directory already exists
|
||||
4. Update main specs from the change's future state specs (see Spec Update Process below)
|
||||
5. Move the entire change directory to the archive location
|
||||
|
||||
WHEN target archive already exists
|
||||
THEN fail with error message
|
||||
AND do not overwrite existing archive
|
||||
|
||||
WHEN move succeeds
|
||||
THEN display success message with archived name and list of updated specs
|
||||
|
||||
### Spec Update Process
|
||||
Before moving the change to archive, the command SHALL update main specs to reflect the deployed reality:
|
||||
|
||||
WHEN the change contains specs in `changes/[name]/specs/`
|
||||
THEN:
|
||||
1. Analyze which specs will be affected by comparing with existing specs
|
||||
2. Display a summary of spec updates to the user (see Confirmation Behavior below)
|
||||
3. Prompt for confirmation unless `--yes` flag is provided
|
||||
4. If confirmed, for each capability spec in the change directory:
|
||||
- Copy the spec from `changes/[name]/specs/[capability]/spec.md` to `openspec/specs/[capability]/spec.md`
|
||||
- Create the target directory structure if it doesn't exist
|
||||
- Overwrite existing spec files (specs represent current reality, change specs are the new reality)
|
||||
- Track which specs were updated for the success message
|
||||
|
||||
WHEN no specs exist in the change
|
||||
THEN skip the spec update step
|
||||
AND proceed with archiving
|
||||
|
||||
### Confirmation Behavior
|
||||
The spec update confirmation SHALL:
|
||||
- Display a clear summary showing:
|
||||
- Which specs will be created (new capabilities)
|
||||
- Which specs will be updated (existing capabilities)
|
||||
- The source path for each spec
|
||||
- Format the confirmation prompt as:
|
||||
```
|
||||
The following specs will be updated:
|
||||
|
||||
NEW specs to be created:
|
||||
- cli-archive (from changes/add-archive-command/specs/cli-archive/spec.md)
|
||||
|
||||
EXISTING specs to be updated:
|
||||
- cli-init (from changes/update-init-command/specs/cli-init/spec.md)
|
||||
|
||||
Update 2 specs and archive 'add-archive-command'? [y/N]:
|
||||
```
|
||||
- Default to "No" for safety (require explicit "y" or "yes")
|
||||
- Skip confirmation when `--yes` or `-y` flag is provided
|
||||
|
||||
WHEN user declines the confirmation
|
||||
THEN abort the entire archive operation
|
||||
AND display message: "Archive cancelled. No changes were made."
|
||||
AND exit with non-zero status code
|
||||
|
||||
## Error Handling
|
||||
|
||||
SHALL handle the following error conditions:
|
||||
- Missing openspec/changes/ directory
|
||||
- Change not found
|
||||
- Archive target already exists
|
||||
- File system permissions issues
|
||||
|
||||
## Why These Decisions
|
||||
|
||||
**Interactive selection**: Reduces typing and helps users see available changes
|
||||
**Task checking**: Prevents accidental archiving of incomplete work
|
||||
**Date prefixing**: Maintains chronological order and prevents naming conflicts
|
||||
**No overwrite**: Preserves historical archives and prevents data loss
|
||||
**Spec updates before archiving**: Specs in the main directory represent current reality; when a change is deployed and archived, its future state specs become the new reality and must replace the main specs
|
||||
**Confirmation for spec updates**: Provides visibility into what will change, prevents accidental overwrites, and ensures users understand the impact before specs are modified
|
||||
**--yes flag for automation**: Allows CI/CD pipelines to archive without interactive prompts while maintaining safety by default for manual use
|
||||
@@ -0,0 +1,44 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. Core Implementation
|
||||
- [ ] 1.1 Create `src/core/archive.ts` with ArchiveCommand class
|
||||
- [ ] 1.1.1 Implement change selection (interactive if not provided)
|
||||
- [ ] 1.1.2 Implement incomplete task checking from tasks.md
|
||||
- [ ] 1.1.3 Implement confirmation prompt for incomplete tasks
|
||||
- [ ] 1.1.4 Implement spec update functionality
|
||||
- [ ] 1.1.4.1 Detect specs in change directory
|
||||
- [ ] 1.1.4.2 Compare with existing main specs
|
||||
- [ ] 1.1.4.3 Display summary of new vs updated specs
|
||||
- [ ] 1.1.4.4 Show confirmation prompt for spec updates
|
||||
- [ ] 1.1.4.5 Copy specs to main spec directory
|
||||
- [ ] 1.1.5 Implement archive move with date prefixing
|
||||
- [ ] 1.1.6 Support --yes flag to skip confirmations
|
||||
|
||||
## 2. CLI Integration
|
||||
- [ ] 2.1 Add archive command to `src/cli/index.ts`
|
||||
- [ ] 2.1.1 Import ArchiveCommand
|
||||
- [ ] 2.1.2 Register command with commander
|
||||
- [ ] 2.1.3 Add --yes/-y flag option
|
||||
- [ ] 2.1.4 Add proper error handling
|
||||
|
||||
## 3. Error Handling
|
||||
- [ ] 3.1 Handle missing openspec/changes/ directory
|
||||
- [ ] 3.2 Handle change not found
|
||||
- [ ] 3.3 Handle archive target already exists
|
||||
- [ ] 3.4 Handle user cancellation
|
||||
|
||||
## 4. Testing
|
||||
- [ ] 4.1 Test with fully completed change
|
||||
- [ ] 4.2 Test with incomplete tasks (warning shown)
|
||||
- [ ] 4.3 Test interactive selection mode
|
||||
- [ ] 4.4 Test duplicate archive prevention
|
||||
- [ ] 4.5 Test spec update functionality
|
||||
- [ ] 4.5.1 Test creating new specs
|
||||
- [ ] 4.5.2 Test updating existing specs
|
||||
- [ ] 4.5.3 Test confirmation prompt display
|
||||
- [ ] 4.5.4 Test declining confirmation (no changes made)
|
||||
- [ ] 4.5.5 Test --yes flag skips confirmation
|
||||
|
||||
## 5. Build and Validation
|
||||
- [ ] 5.1 Ensure TypeScript compilation succeeds
|
||||
- [ ] 5.2 Test command execution
|
||||
@@ -0,0 +1,19 @@
|
||||
# Add Diff Command to OpenSpec CLI
|
||||
|
||||
## Why
|
||||
|
||||
Developers need to easily view differences between proposed spec changes and current specs without manually comparing files.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add `openspec diff [change-name]` command that shows differences between change specs and current specs
|
||||
- Compare files in `changes/[change-name]/specs/` with corresponding files in `specs/`
|
||||
- Display unified diff output showing added/removed/modified lines
|
||||
- Support colored output for better readability
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: New capability `cli-diff` will be added
|
||||
- Affected code:
|
||||
- `src/cli/index.ts` - Add diff command
|
||||
- `src/core/diff.ts` - New file with diff logic (~80 lines)
|
||||
@@ -0,0 +1,77 @@
|
||||
# CLI Diff Command Specification
|
||||
|
||||
## Purpose
|
||||
|
||||
The `openspec diff` command provides developers with a visual comparison between proposed spec changes and the current deployed specs.
|
||||
|
||||
## Command Syntax
|
||||
|
||||
```bash
|
||||
openspec diff [change-name]
|
||||
```
|
||||
|
||||
## Behavior
|
||||
|
||||
### Without Arguments
|
||||
|
||||
WHEN running `openspec diff` without arguments
|
||||
THEN list all available changes in the `changes/` directory (excluding archive)
|
||||
AND prompt user to select a change
|
||||
|
||||
### With Change Name
|
||||
|
||||
WHEN running `openspec diff <change-name>`
|
||||
THEN compare all spec files in `changes/<change-name>/specs/` with corresponding files in `specs/`
|
||||
|
||||
### Diff Output
|
||||
|
||||
FOR each spec file in the change:
|
||||
- IF file exists in both locations THEN show unified diff
|
||||
- IF file only exists in change THEN show as new file (all lines with +)
|
||||
- IF file only exists in current specs THEN show as deleted (all lines with -)
|
||||
|
||||
### Display Format
|
||||
|
||||
The diff SHALL use standard unified diff format:
|
||||
- Lines prefixed with `-` for removed content
|
||||
- Lines prefixed with `+` for added content
|
||||
- Lines without prefix for unchanged context
|
||||
- File headers showing the paths being compared
|
||||
|
||||
### Color Support
|
||||
|
||||
WHEN terminal supports colors:
|
||||
- Removed lines displayed in red
|
||||
- Added lines displayed in green
|
||||
- File headers displayed in bold
|
||||
- Context lines in default color
|
||||
|
||||
### Error Handling
|
||||
|
||||
WHEN specified change doesn't exist THEN display error "Change '<name>' not found"
|
||||
WHEN no specs directory in change THEN display "No spec changes found for '<name>'"
|
||||
WHEN changes directory doesn't exist THEN display "No OpenSpec changes directory found"
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
# View diff for specific change
|
||||
$ openspec diff add-auth-feature
|
||||
|
||||
--- specs/user-auth/spec.md
|
||||
+++ changes/add-auth-feature/specs/user-auth/spec.md
|
||||
@@ -10,6 +10,8 @@
|
||||
Users SHALL authenticate with email and password.
|
||||
|
||||
+Users MAY authenticate with OAuth providers.
|
||||
+
|
||||
WHEN credentials are valid THEN issue JWT token.
|
||||
|
||||
# List all changes and select
|
||||
$ openspec diff
|
||||
Available changes:
|
||||
1. add-auth-feature
|
||||
2. update-payment-flow
|
||||
3. add-status-command
|
||||
Select a change (1-3):
|
||||
```
|
||||
@@ -0,0 +1,23 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. Core Implementation
|
||||
- [x] 1.1 Create `src/core/diff.ts` with diff logic
|
||||
- [x] 1.2 Implement change directory scanning
|
||||
- [x] 1.3 Implement file comparison using unified diff format
|
||||
- [x] 1.4 Add color support for terminal output
|
||||
|
||||
## 2. CLI Integration
|
||||
- [x] 2.1 Add diff command to `src/cli/index.ts`
|
||||
- [x] 2.2 Implement interactive change selection when no argument provided
|
||||
- [x] 2.3 Add error handling for missing changes
|
||||
|
||||
## 3. Enhancements
|
||||
- [x] 3.1 Replace with jest-diff for professional diff output
|
||||
- [x] 3.2 Improve file headers with status and statistics
|
||||
- [x] 3.3 Add summary view with file counts and line changes
|
||||
|
||||
## 4. Testing
|
||||
- [ ] 4.1 Test diff generation for modified files
|
||||
- [ ] 4.2 Test handling of new files
|
||||
- [ ] 4.3 Test handling of deleted files
|
||||
- [ ] 4.4 Test interactive mode
|
||||
@@ -0,0 +1,56 @@
|
||||
# Design: Change Commands
|
||||
|
||||
## Architecture Decisions
|
||||
|
||||
### Command Structure
|
||||
Similar to spec commands, we use subcommands (`change show`, `change list`, `change validate`) for:
|
||||
- Consistency with spec command pattern
|
||||
- Clear separation of concerns
|
||||
- Future extensibility for change management features
|
||||
|
||||
### JSON Schema for Changes
|
||||
```typescript
|
||||
{
|
||||
version: string, // Schema version
|
||||
format: "change", // Identifies as change document
|
||||
sourcePath: string, // Original markdown file path
|
||||
id: string, // Change identifier
|
||||
title: string, // Change title
|
||||
why: string, // Motivation section
|
||||
whatChanges: Array<{
|
||||
type: "ADDED" | "MODIFIED" | "REMOVED" | "RENAMED",
|
||||
deltas: Array<{
|
||||
specId: string,
|
||||
description: string,
|
||||
requirements?: Array<Requirement> // Only for ADDED/MODIFIED
|
||||
}>
|
||||
}>
|
||||
}
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- Group deltas by operation type for clearer organization
|
||||
- Optional requirements field (only relevant for ADDED/MODIFIED)
|
||||
- Reuse RequirementSchema from spec commands for consistency
|
||||
|
||||
### Delta Operations
|
||||
**Four operation types:**
|
||||
1. **ADDED**: New requirements added to specs
|
||||
2. **MODIFIED**: Changes to existing requirements
|
||||
3. **REMOVED**: Requirements being deleted
|
||||
4. **RENAMED**: Spec identifier changes
|
||||
|
||||
**Design choice:** Explicit operation types rather than diff-based approach for:
|
||||
- Human readability in markdown
|
||||
- Clear intent communication
|
||||
- Easier validation and tooling
|
||||
|
||||
### Dependency on Spec Commands
|
||||
- **Shared schemas**: RequirementSchema and ScenarioSchema reused
|
||||
- **Implementation order**: spec commands must be implemented first
|
||||
- **Common parser utilities**: Share markdown parsing logic
|
||||
|
||||
### Legacy Compatibility
|
||||
- Keep existing `list` command functional with deprecation warning
|
||||
- Migration path: `list` → `change list` with same functionality
|
||||
- Gradual transition to avoid breaking existing workflows
|
||||
@@ -0,0 +1,17 @@
|
||||
# Change: Add Change Commands with JSON Output
|
||||
|
||||
## Why
|
||||
|
||||
OpenSpec change proposals currently can only be viewed as markdown files, creating the same programmatic access limitations as specs. Additionally, the current `openspec list` command only lists changes, which is inconsistent with the new resource-based command structure.
|
||||
|
||||
## What Changes
|
||||
|
||||
- **cli-change:** Add new command for managing change proposals with show, list, and validate subcommands
|
||||
- **cli-list:** Add deprecation notice for legacy list command to guide users to the new change list command
|
||||
|
||||
## Impact
|
||||
|
||||
- **Affected specs**: cli-list (modify to add deprecation notice)
|
||||
- **Affected code**:
|
||||
- src/cli/index.ts (register new command)
|
||||
- src/core/list.ts (add deprecation notice)
|
||||
@@ -0,0 +1,48 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Change Command
|
||||
|
||||
The system SHALL provide a `change` command with subcommands for displaying, listing, and validating change proposals.
|
||||
|
||||
#### Scenario: Show change as JSON
|
||||
|
||||
- **WHEN** executing `openspec change show update-error --json`
|
||||
- **THEN** parse the markdown change file
|
||||
- **AND** extract change structure and deltas
|
||||
- **AND** output valid JSON to stdout
|
||||
|
||||
#### Scenario: List all changes
|
||||
|
||||
- **WHEN** executing `openspec change list`
|
||||
- **THEN** scan the openspec/changes directory
|
||||
- **AND** return list of all pending changes
|
||||
- **AND** support JSON output with `--json` flag
|
||||
|
||||
#### Scenario: Show only requirement changes
|
||||
|
||||
- **WHEN** executing `openspec change show update-error --requirements-only`
|
||||
- **THEN** display only the requirement changes (ADDED/MODIFIED/REMOVED/RENAMED)
|
||||
- **AND** exclude why and what changes sections
|
||||
|
||||
#### Scenario: Validate change structure
|
||||
|
||||
- **WHEN** executing `openspec change validate update-error`
|
||||
- **THEN** parse the change file
|
||||
- **AND** validate against Zod schema
|
||||
- **AND** ensure deltas are well-formed
|
||||
|
||||
### Requirement: Legacy Compatibility
|
||||
|
||||
The system SHALL maintain backward compatibility with the existing `list` command while showing deprecation notices.
|
||||
|
||||
#### Scenario: Legacy list command
|
||||
|
||||
- **WHEN** executing `openspec list`
|
||||
- **THEN** display current list of changes (existing behavior)
|
||||
- **AND** show deprecation notice: "Note: 'openspec list' is deprecated. Use 'openspec change list' instead."
|
||||
|
||||
#### Scenario: Legacy list with --all flag
|
||||
|
||||
- **WHEN** executing `openspec list --all`
|
||||
- **THEN** display all changes (existing behavior)
|
||||
- **AND** show same deprecation notice
|
||||
@@ -0,0 +1,12 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Command Execution
|
||||
|
||||
The current `list` command behavior SHALL be preserved but marked as deprecated.
|
||||
|
||||
#### Scenario: Deprecation notice
|
||||
|
||||
- **WHEN** using the legacy `list` command
|
||||
- **THEN** continue to work as before
|
||||
- **AND** display deprecation notice
|
||||
- **AND** suggest using `openspec change list` instead
|
||||
@@ -0,0 +1,34 @@
|
||||
# Implementation Tasks (Phase 2: Builds on add-zod-validation)
|
||||
|
||||
## 1. Command Implementation
|
||||
- [x] 1.1 Create src/commands/change.ts
|
||||
- [x] 1.2 Import ChangeSchema and DeltaSchema from src/core/schemas/change.schema.ts
|
||||
- [x] 1.3 Import markdown parser from src/core/parsers/markdown-parser.ts
|
||||
- [x] 1.4 Import ChangeValidator from src/core/validation/validator.ts
|
||||
- [x] 1.5 Import JSON converter from src/core/converters/json-converter.ts
|
||||
- [x] 1.6 Implement show subcommand with JSON output using existing converter
|
||||
- [x] 1.7 Implement list subcommand
|
||||
- [x] 1.8 Implement validate subcommand using existing ChangeValidator
|
||||
- [x] 1.9 Add --requirements-only filtering option
|
||||
- [x] 1.10 Add --strict mode support (leveraging existing validation infrastructure)
|
||||
- [x] 1.11 Add --json flag for validation reports
|
||||
|
||||
## 2. Change-Specific Parser Extensions
|
||||
- [x] 2.1 Create src/core/parsers/change-parser.ts (extends base markdown parser)
|
||||
- [x] 2.2 Parse proposal structure (Why, What Changes sections)
|
||||
- [x] 2.3 Extract ADDED/MODIFIED/REMOVED/RENAMED sections
|
||||
- [x] 2.4 Parse delta operations within each section
|
||||
- [x] 2.5 Add tests for change parser
|
||||
|
||||
## 3. Legacy Compatibility
|
||||
- [x] 3.1 Update src/core/list.ts to add deprecation notice
|
||||
- [x] 3.2 Ensure existing list command continues to work
|
||||
- [x] 3.3 Add console warning for deprecated command usage
|
||||
|
||||
## 4. Integration
|
||||
- [x] 4.1 Register change command in src/cli/index.ts
|
||||
- [ ] 4.2 Add integration tests for all subcommands
|
||||
- [x] 4.3 Test JSON output for changes
|
||||
- [x] 4.4 Test legacy compatibility
|
||||
- [x] 4.5 Test validation with strict mode
|
||||
- [x] 4.6 Update CLI help documentation (add 'change' command to main help, document subcommands: show, list, validate)
|
||||
@@ -0,0 +1,20 @@
|
||||
## Why
|
||||
|
||||
Users frequently need to view changes and specs but must know in advance whether they're looking at a change or spec. The current subcommand structure (`change show`, `spec show`) creates friction when:
|
||||
- Users want to quickly view an item without remembering its type
|
||||
- Exploring the codebase requires switching between different show commands
|
||||
- Show commands without arguments return errors instead of helpful guidance
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add new top-level `show` command for displaying changes or specs with intelligent selection
|
||||
- Support direct item display: `openspec show <item>` with automatic type detection
|
||||
- Interactive selection when no arguments provided
|
||||
- Enhance existing `change show` and `spec show` to support interactive selection (backwards compatibility)
|
||||
- Maintain all existing format options (--json, --deltas-only, --requirements, etc.)
|
||||
|
||||
## Impact
|
||||
|
||||
- New specs to create: cli-show
|
||||
- Specs to enhance: cli-change, cli-spec (for backwards compatibility)
|
||||
- Affected code: src/cli/index.ts, src/commands/show.ts (new), src/commands/spec.ts, src/commands/change.ts
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# CLI Change Command Spec
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Interactive show selection
|
||||
|
||||
The change show command SHALL support interactive selection when no change name is provided.
|
||||
|
||||
#### Scenario: Interactive change selection for show
|
||||
|
||||
- **WHEN** executing `openspec change show` without arguments
|
||||
- **THEN** display an interactive list of available changes
|
||||
- **AND** allow the user to select a change to show
|
||||
- **AND** display the selected change content
|
||||
- **AND** maintain all existing show options (--json, --deltas-only)
|
||||
|
||||
#### Scenario: Non-interactive fallback keeps current behavior
|
||||
|
||||
- **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0`
|
||||
- **WHEN** executing `openspec change show` without a change name
|
||||
- **THEN** do not prompt interactively
|
||||
- **AND** print the existing hint including available change IDs
|
||||
- **AND** set `process.exitCode = 1`
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
# CLI Show Command Spec
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Top-level show command
|
||||
|
||||
The CLI SHALL provide a top-level `show` command for displaying changes and specs with intelligent selection.
|
||||
|
||||
#### Scenario: Interactive show selection
|
||||
|
||||
- **WHEN** executing `openspec show` without arguments
|
||||
- **THEN** prompt user to select type (change or spec)
|
||||
- **AND** display list of available items for selected type
|
||||
- **AND** show the selected item's content
|
||||
|
||||
#### Scenario: Non-interactive environments do not prompt
|
||||
|
||||
- **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0`
|
||||
- **WHEN** executing `openspec show` without arguments
|
||||
- **THEN** do not prompt
|
||||
- **AND** print a helpful hint with examples for `openspec show <item>` or `openspec change/spec show`
|
||||
- **AND** exit with code 1
|
||||
|
||||
#### Scenario: Direct item display
|
||||
|
||||
- **WHEN** executing `openspec show <item-name>`
|
||||
- **THEN** automatically detect if item is a change or spec
|
||||
- **AND** display the item's content
|
||||
- **AND** use appropriate formatting based on item type
|
||||
|
||||
#### Scenario: Type detection and ambiguity handling
|
||||
|
||||
- **WHEN** executing `openspec show <item-name>`
|
||||
- **THEN** if `<item-name>` uniquely matches a change or a spec, show that item
|
||||
- **AND** if it matches both, print an ambiguity error and suggest `--type change|spec` or using `openspec change show`/`openspec spec show`
|
||||
- **AND** if it matches neither, print not-found with nearest-match suggestions
|
||||
|
||||
#### Scenario: Explicit type override
|
||||
|
||||
- **WHEN** executing `openspec show --type change <item>`
|
||||
- **THEN** treat `<item>` as a change ID and show it (skipping auto-detection)
|
||||
|
||||
- **WHEN** executing `openspec show --type spec <item>`
|
||||
- **THEN** treat `<item>` as a spec ID and show it (skipping auto-detection)
|
||||
|
||||
### Requirement: Output format options
|
||||
|
||||
The show command SHALL support various output formats consistent with existing commands.
|
||||
|
||||
#### Scenario: JSON output
|
||||
|
||||
- **WHEN** executing `openspec show <item> --json`
|
||||
- **THEN** output the item in JSON format
|
||||
- **AND** include parsed metadata and structure
|
||||
- **AND** maintain format consistency with existing change/spec show commands
|
||||
|
||||
#### Scenario: Flag scoping and delegation
|
||||
|
||||
- **WHEN** showing a change or a spec via the top-level command
|
||||
- **THEN** accept common flags such as `--json`
|
||||
- **AND** pass through type-specific flags to the corresponding implementation
|
||||
- Change-only flags: `--deltas-only` (alias `--requirements-only` deprecated)
|
||||
- Spec-only flags: `--requirements`, `--no-scenarios`, `-r/--requirement`
|
||||
- **AND** ignore irrelevant flags for the detected type with a warning
|
||||
|
||||
### Requirement: Interactivity controls
|
||||
|
||||
- The CLI SHALL respect `--no-interactive` to disable prompts.
|
||||
- The CLI SHALL respect `OPEN_SPEC_INTERACTIVE=0` to disable prompts globally.
|
||||
- Interactive prompts SHALL only be shown when stdin is a TTY and interactivity is not disabled.
|
||||
|
||||
#### Scenario: Change-specific options
|
||||
|
||||
- **WHEN** showing a change with `openspec show <change-name> --deltas-only`
|
||||
- **THEN** display only the deltas in JSON format
|
||||
- **AND** maintain compatibility with existing change show options
|
||||
|
||||
#### Scenario: Spec-specific options
|
||||
|
||||
- **WHEN** showing a spec with `openspec show <spec-id> --requirements`
|
||||
- **THEN** display only requirements in JSON format
|
||||
- **AND** support other spec options (--no-scenarios, -r)
|
||||
- **AND** maintain compatibility with existing spec show options
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# CLI Spec Command Spec
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Interactive spec show
|
||||
|
||||
The spec show command SHALL support interactive selection when no spec-id is provided.
|
||||
|
||||
#### Scenario: Interactive spec selection for show
|
||||
|
||||
- **WHEN** executing `openspec spec show` without arguments
|
||||
- **THEN** display an interactive list of available specs
|
||||
- **AND** allow the user to select a spec to show
|
||||
- **AND** display the selected spec content
|
||||
- **AND** maintain all existing show options (--json, --requirements, --no-scenarios, -r)
|
||||
|
||||
#### Scenario: Non-interactive fallback keeps current behavior
|
||||
|
||||
- **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0`
|
||||
- **WHEN** executing `openspec spec show` without a spec-id
|
||||
- **THEN** do not prompt interactively
|
||||
- **AND** print the existing error message for missing spec-id
|
||||
- **AND** set non-zero exit code
|
||||
@@ -0,0 +1,142 @@
|
||||
# Implementation Tasks — Add Interactive Show Command
|
||||
|
||||
## Goals
|
||||
- Add a top-level `show` command with intelligent selection and type detection.
|
||||
- Add interactive selection to `change show` and `spec show` when no ID is provided.
|
||||
- Preserve raw-first output behavior and existing JSON formats/filters.
|
||||
- Respect `--no-interactive` and `OPEN_SPEC_INTERACTIVE=0` consistently.
|
||||
|
||||
---
|
||||
|
||||
## 1) CLI wiring
|
||||
- [x] In `src/cli/index.ts` add a top-level command: `program.command('show [item-name]')`
|
||||
- Options:
|
||||
- `--json`
|
||||
- `--type <type>` where `<type>` is `change|spec`
|
||||
- `--no-interactive`
|
||||
- Allow passing-through type-specific flags using `.allowUnknownOption(true)` so the top-level can forward flags to the underlying type handler.
|
||||
- Action: instantiate `new ShowCommand().execute(itemName, options)`.
|
||||
- [x] Update `change show` subcommand to accept `--no-interactive` and pass it to `ChangeCommand.show(...)`.
|
||||
- [x] Change `spec show` subcommand to accept optional ID (`show [spec-id]`), add `--no-interactive`, and pass to spec show implementation.
|
||||
|
||||
Acceptance:
|
||||
- `openspec show` exists and prints a helpful hint in non-interactive contexts when no args.
|
||||
- Unknown flags for other types do not crash parsing; they are warned/ignored appropriately.
|
||||
|
||||
---
|
||||
|
||||
## 2) New module: `src/commands/show.ts`
|
||||
- [x] Create `ShowCommand` with:
|
||||
- `execute(itemName?: string, options?: { json?: boolean; type?: string; noInteractive?: boolean; [k: string]: any })`
|
||||
- Interactive path when `!itemName` and interactive is enabled:
|
||||
- Prompt: "What would you like to show?" → `change` or `spec`.
|
||||
- Load available IDs for the chosen type and prompt selection.
|
||||
- Delegate to type-specific show implementation.
|
||||
- Non-interactive path when `!itemName`:
|
||||
- Print hint with examples:
|
||||
- `openspec show <item>`
|
||||
- `openspec change show`
|
||||
- `openspec spec show`
|
||||
- Exit with code 1.
|
||||
- Direct item path when `itemName` is provided:
|
||||
- Type override via `--type` takes precedence.
|
||||
- Otherwise detect using `getActiveChangeIds()` and `getSpecIds()`.
|
||||
- If ambiguous and no override: print error + suggestion to pass `--type` or use subcommands; exit code 1.
|
||||
- If unknown: print not-found with nearest-match suggestions; exit code 1.
|
||||
- On success: delegate to type-specific show.
|
||||
- [x] Flag scoping and pass-through:
|
||||
- Common: `--json` → forwarded to both types.
|
||||
- Change-only: `--deltas-only`, `--requirements-only` (deprecated alias).
|
||||
- Spec-only: `--requirements`, `--no-scenarios`, `-r/--requirement`.
|
||||
- Warn and ignore irrelevant flags for the resolved type.
|
||||
|
||||
Acceptance:
|
||||
- `openspec show <change-id> --json --deltas-only` matches `openspec change show <id> --json --deltas-only` output.
|
||||
- `openspec show <spec-id> --json --requirements` matches `openspec spec show <id> --json --requirements` output.
|
||||
- Ambiguity and not-found behaviors match the `cli-show` spec.
|
||||
|
||||
---
|
||||
|
||||
## 3) Refactor spec show into reusable API
|
||||
- [x] In `src/commands/spec.ts`, extract show logic into an exported `SpecCommand` with `show(specId?: string, options?: { json?: boolean; requirements?: boolean; scenarios?: boolean; requirement?: string; noInteractive?: boolean })`.
|
||||
- Reuse current helpers (`parseSpecFromFile`, `filterSpec`, raw-first printing).
|
||||
- Keep `registerSpecCommand` but delegate to `new SpecCommand().show(...)`.
|
||||
- [x] Update CLI spec show subcommand to optional arg and interactive behavior (see section 4).
|
||||
|
||||
Acceptance:
|
||||
- Existing `spec show` tests continue to pass.
|
||||
- New `SpecCommand.show` can be called from `ShowCommand`.
|
||||
|
||||
---
|
||||
|
||||
## 4) Backwards-compatible interactive in subcommands
|
||||
- [x] `src/commands/change.ts` → extend `show(changeName?: string, options?: { json?: boolean; requirementsOnly?: boolean; deltasOnly?: boolean; noInteractive?: boolean })`:
|
||||
- When `!changeName` and interactive enabled: prompt from `getActiveChangeIds()` and show the selected change.
|
||||
- Non-interactive fallback: keep current behavior (print available IDs + `openspec change list` hint, set `process.exitCode = 1`).
|
||||
- [x] `src/commands/spec.ts` → `SpecCommand.show` as above:
|
||||
- When `!specId` and interactive enabled: prompt from `getSpecIds()` and show the selected spec.
|
||||
- Non-interactive fallback: print the same error as existing behavior for missing `<spec-id>` and set non-zero exit code.
|
||||
|
||||
Acceptance:
|
||||
- `openspec change show` in non-interactive prints list hint and exits non-zero.
|
||||
- `openspec spec show` in non-interactive prints missing-arg error and exits non-zero.
|
||||
|
||||
---
|
||||
|
||||
## 5) Shared utilities
|
||||
- [x] Extract `nearestMatches` and `levenshtein` from `src/commands/validate.ts` into `src/utils/match.ts` (exported helpers).
|
||||
- [x] Update `ValidateCommand` and new `ShowCommand` to import from `utils/match`.
|
||||
|
||||
Acceptance:
|
||||
- Build succeeds with shared helpers and no duplication.
|
||||
|
||||
---
|
||||
|
||||
## 6) Hints, warnings, and messages
|
||||
- [x] Top-level `show` hint (non-interactive no-arg):
|
||||
- Lines include: `openspec show <item>`, `openspec change show`, `openspec spec show`, and "Or run in an interactive terminal.".
|
||||
- [x] Ambiguity message suggests `--type change|spec` and the subcommands.
|
||||
- [x] Not-found suggests nearest matches (up to 5).
|
||||
- [x] Irrelevant flag warnings for the resolved type (printed to stderr, no crash).
|
||||
|
||||
Acceptance:
|
||||
- Messages match the `cli-show` spec wording intent and style used elsewhere.
|
||||
|
||||
---
|
||||
|
||||
## 7) Tests
|
||||
Add tests mirroring existing patterns (non-TTY simulation via `OPEN_SPEC_INTERACTIVE=0`).
|
||||
|
||||
- [x] `test/commands/show.test.ts`
|
||||
- Non-interactive, no arg → prints hint and exits non-zero.
|
||||
- Direct item detection for change and for spec.
|
||||
- Ambiguity case when both exist → error and suggestion for `--type`.
|
||||
- Not-found case → nearest-match suggestions.
|
||||
- Pass-through flags: change `--json --deltas-only`, spec `--json --requirements`.
|
||||
- [x] `test/commands/change.interactive-show.test.ts` (non-interactive fallback)
|
||||
- Ensure `openspec change show` without args prints available IDs + list hint and non-zero exit.
|
||||
- [x] `test/commands/spec.interactive-show.test.ts` (non-interactive fallback)
|
||||
- Ensure `openspec spec show` without args prints missing-arg error and non-zero exit.
|
||||
|
||||
Acceptance:
|
||||
- All new tests pass after build; no regressions in existing tests.
|
||||
|
||||
---
|
||||
|
||||
## 8) Documentation (optional but recommended)
|
||||
- [x] Update `openspec/README.md` usage examples to include the new `show` command with type detection and flags.
|
||||
|
||||
---
|
||||
|
||||
## 9) Non-functional checks
|
||||
- [x] Run `pnpm build` and all tests (`pnpm test`).
|
||||
- [x] Ensure no linter/type errors and messages are consistent with existing style.
|
||||
|
||||
---
|
||||
|
||||
## Notes on consistency
|
||||
- Follow raw-first behavior for text output: passthrough file content with no formatting, mirroring current `change show` and `spec show`.
|
||||
- Reuse `isInteractive` and `item-discovery` helpers for consistent prompting behavior.
|
||||
- Keep JSON output shapes identical to current `ChangeCommand.show` and `spec show` outputs.
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
## Why
|
||||
The archive command currently forces users to either accept spec updates or cancel the entire archive operation. Users need flexibility to archive changes without updating specs, either through explicit flags or by declining the confirmation prompt. This is especially important for changes that don't modify specs (like tooling, documentation, or infrastructure updates).
|
||||
|
||||
## What Changes
|
||||
- Add new `--skip-specs` flag to the archive command that bypasses all spec update operations
|
||||
- Fix confirmation behavior: when users decline spec updates interactively, proceed with archiving instead of cancelling the entire operation
|
||||
- When `--skip-specs` flag is used, skip both the spec discovery and update confirmation steps entirely
|
||||
- Display clear message when specs are skipped (either via flag or user choice)
|
||||
- Flag can be combined with existing `--yes` flag for fully automated archiving without spec updates
|
||||
|
||||
## Impact
|
||||
- Affected specs: cli-archive
|
||||
- Affected code: src/core/archive.ts, src/cli/index.ts
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
# CLI Archive Command Specification
|
||||
|
||||
## Purpose
|
||||
The archive command moves completed changes from the active changes directory to the archive folder with date-based naming, following OpenSpec conventions.
|
||||
|
||||
## Command Syntax
|
||||
```bash
|
||||
openspec archive [change-name] [--yes|-y] [--skip-specs]
|
||||
```
|
||||
|
||||
Options:
|
||||
- `--yes`, `-y`: Skip confirmation prompts (for automation)
|
||||
- `--skip-specs`: Skip spec update operations entirely (for changes without spec modifications)
|
||||
|
||||
## Behavior
|
||||
|
||||
### Requirement: Change Selection
|
||||
|
||||
The command SHALL support both interactive and direct change selection methods.
|
||||
|
||||
#### Scenario: Interactive selection
|
||||
|
||||
- **WHEN** no change-name is provided
|
||||
- **THEN** display interactive list of available changes (excluding archive/)
|
||||
- **AND** allow user to select one
|
||||
|
||||
#### Scenario: Direct selection
|
||||
|
||||
- **WHEN** change-name is provided
|
||||
- **THEN** use that change directly
|
||||
- **AND** validate it exists
|
||||
|
||||
### Requirement: Task Completion Check
|
||||
|
||||
The command SHALL verify task completion status before archiving to prevent premature archival.
|
||||
|
||||
#### Scenario: Incomplete tasks found
|
||||
|
||||
- **WHEN** incomplete tasks are found (marked with `- [ ]`)
|
||||
- **THEN** display all incomplete tasks to the user
|
||||
- **AND** prompt for confirmation to continue
|
||||
- **AND** default to "No" for safety
|
||||
|
||||
#### Scenario: All tasks complete
|
||||
|
||||
- **WHEN** all tasks are complete OR no tasks.md exists
|
||||
- **THEN** proceed with archiving without prompting
|
||||
|
||||
### Requirement: Archive Process
|
||||
|
||||
The archive operation SHALL follow a structured process to safely move changes to the archive.
|
||||
|
||||
#### Scenario: Performing archive
|
||||
|
||||
- **WHEN** archiving a change
|
||||
- **THEN** execute these steps:
|
||||
1. Create archive/ directory if it doesn't exist
|
||||
2. Generate target name as `YYYY-MM-DD-[change-name]` using current date
|
||||
3. Check if target directory already exists
|
||||
4. Update main specs from the change's future state specs unless `--skip-specs` is provided (see Spec Update Process below)
|
||||
5. Move the entire change directory to the archive location
|
||||
|
||||
#### Scenario: Archive already exists
|
||||
|
||||
- **WHEN** target archive already exists
|
||||
- **THEN** fail with error message
|
||||
- **AND** do not overwrite existing archive
|
||||
|
||||
#### Scenario: Successful archive
|
||||
|
||||
- **WHEN** move succeeds
|
||||
- **THEN** display success message with archived name and list of updated specs (if any)
|
||||
|
||||
### Requirement: Spec Update Process
|
||||
|
||||
Before moving the change to archive, the command SHALL update main specs to reflect the deployed reality unless the `--skip-specs` flag is provided.
|
||||
|
||||
#### Scenario: Skipping spec updates
|
||||
|
||||
- **WHEN** the `--skip-specs` flag is provided
|
||||
- **THEN** skip all spec discovery and update operations
|
||||
- **AND** proceed directly to moving the change to archive
|
||||
- **AND** display message indicating specs were skipped
|
||||
|
||||
#### Scenario: Updating specs from change
|
||||
|
||||
- **WHEN** the change contains specs in `changes/[name]/specs/` AND `--skip-specs` is NOT provided
|
||||
- **THEN** execute these steps:
|
||||
1. Analyze which specs will be affected by comparing with existing specs
|
||||
2. Display a summary of spec updates to the user (see Confirmation Behavior below)
|
||||
3. Prompt for confirmation unless `--yes` flag is provided
|
||||
4. If confirmed, for each capability spec in the change directory:
|
||||
- Copy the spec from `changes/[name]/specs/[capability]/spec.md` to `openspec/specs/[capability]/spec.md`
|
||||
- Create the target directory structure if it doesn't exist
|
||||
- Overwrite existing spec files (specs represent current reality, change specs are the new reality)
|
||||
- Track which specs were updated for the success message
|
||||
|
||||
#### Scenario: No specs in change
|
||||
|
||||
- **WHEN** no specs exist in the change AND `--skip-specs` is NOT provided
|
||||
- **THEN** skip the spec update step
|
||||
- **AND** proceed with archiving
|
||||
|
||||
### Requirement: Confirmation Behavior
|
||||
|
||||
The spec update confirmation SHALL provide clear visibility into changes before they are applied.
|
||||
|
||||
#### Scenario: Displaying confirmation
|
||||
|
||||
- **WHEN** prompting for confirmation AND `--skip-specs` is NOT provided
|
||||
- **THEN** display a clear summary showing:
|
||||
- Which specs will be created (new capabilities)
|
||||
- Which specs will be updated (existing capabilities)
|
||||
- The source path for each spec
|
||||
- **AND** format the confirmation prompt as:
|
||||
```
|
||||
The following specs will be updated:
|
||||
|
||||
NEW specs to be created:
|
||||
- cli-archive (from changes/add-archive-command/specs/cli-archive/spec.md)
|
||||
|
||||
EXISTING specs to be updated:
|
||||
- cli-init (from changes/update-init-command/specs/cli-init/spec.md)
|
||||
|
||||
Update 2 specs and archive 'add-archive-command'? [y/N]:
|
||||
```
|
||||
#### Scenario: Handling confirmation response
|
||||
|
||||
- **WHEN** waiting for user confirmation
|
||||
- **THEN** default to "No" for safety (require explicit "y" or "yes")
|
||||
- **AND** skip confirmation when `--yes` or `-y` flag is provided
|
||||
- **AND** skip entire spec confirmation when `--skip-specs` flag is provided
|
||||
|
||||
#### Scenario: User declines spec update confirmation
|
||||
|
||||
- **WHEN** user declines the spec update confirmation
|
||||
- **THEN** skip the spec update operations
|
||||
- **AND** display message: "Skipping spec updates. Proceeding with archive."
|
||||
- **AND** continue with the archive operation
|
||||
- **AND** display success message indicating specs were not updated
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Requirement: Error Conditions
|
||||
|
||||
The command SHALL handle various error conditions gracefully.
|
||||
|
||||
#### Scenario: Handling errors
|
||||
|
||||
- **WHEN** errors occur
|
||||
- **THEN** handle the following conditions:
|
||||
- Missing openspec/changes/ directory
|
||||
- Change not found
|
||||
- Archive target already exists
|
||||
- File system permissions issues
|
||||
|
||||
## Why These Decisions
|
||||
|
||||
**Interactive selection**: Reduces typing and helps users see available changes
|
||||
**Task checking**: Prevents accidental archiving of incomplete work
|
||||
**Date prefixing**: Maintains chronological order and prevents naming conflicts
|
||||
**No overwrite**: Preserves historical archives and prevents data loss
|
||||
**Spec updates before archiving**: Specs in the main directory represent current reality; when a change is deployed and archived, its future state specs become the new reality and must replace the main specs
|
||||
**Confirmation for spec updates**: Provides visibility into what will change, prevents accidental overwrites, and ensures users understand the impact before specs are modified
|
||||
**Non-blocking confirmation**: Declining spec updates doesn't cancel archiving - users can review specs and choose to update them separately if needed
|
||||
**--yes flag for automation**: Allows CI/CD pipelines to archive without interactive prompts while maintaining safety by default for manual use
|
||||
**--skip-specs flag**: Enables archiving of changes that don't modify specs (like infrastructure, tooling, or documentation changes) without unnecessary spec update prompts or operations
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Skip Specs Option
|
||||
|
||||
The archive command SHALL support a `--skip-specs` flag that skips all spec update operations and proceeds directly to archiving.
|
||||
|
||||
#### Scenario: Skipping spec updates with flag
|
||||
|
||||
- **WHEN** executing `openspec archive <change> --skip-specs`
|
||||
- **THEN** skip spec discovery and update confirmation
|
||||
- **AND** proceed directly to moving the change to archive
|
||||
- **AND** display a message indicating specs were skipped
|
||||
|
||||
### Requirement: Non-blocking confirmation
|
||||
|
||||
The archive operation SHALL proceed when the user declines spec updates instead of cancelling the entire operation.
|
||||
|
||||
#### Scenario: User declines spec update confirmation
|
||||
|
||||
- **WHEN** the user declines spec update confirmation
|
||||
- **THEN** skip spec updates
|
||||
- **AND** continue with the archive operation
|
||||
- **AND** display a success message indicating specs were not updated
|
||||
@@ -0,0 +1,57 @@
|
||||
## 1. Update Archive Command Implementation
|
||||
- [x] 1.1 Add `skipSpecs` option to the archive command options interface
|
||||
- [x] 1.2 Modify the execute method to skip spec operations when flag is set
|
||||
- [x] 1.3 Fix confirmation behavior: when user declines spec updates, proceed with archiving instead of cancelling
|
||||
- [x] 1.4 Update console output to indicate when specs are being skipped (via flag or user choice)
|
||||
- [x] 1.5 Ensure archive continues after declining spec updates
|
||||
|
||||
## 2. Update CLI Interface
|
||||
- [x] 2.1 Add `--skip-specs` flag to the archive command definition
|
||||
- [x] 2.2 Pass the flag value to the archive command execute method
|
||||
|
||||
## 3. Update Tests
|
||||
- [x] 3.1 Add test case for archiving with --skip-specs flag
|
||||
- [x] 3.2 Add test case for declining spec updates but continuing with archive
|
||||
- [x] 3.3 Verify that spec updates are skipped when flag is used
|
||||
- [x] 3.4 Verify that archive proceeds when user declines spec updates
|
||||
- [x] 3.5 Ensure existing behavior remains unchanged when flag is not used
|
||||
|
||||
## 4. Update Documentation
|
||||
- [x] 4.1 Update the cli-archive spec to document the new --skip-specs flag
|
||||
- [x] 4.2 Document the new behavior when declining spec updates interactively
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### Key Design Decisions
|
||||
|
||||
1. **Non-blocking Confirmation Behavior**: When users decline spec updates interactively, the archive operation continues rather than cancelling entirely. This was a critical UX improvement because:
|
||||
- Users may want to review specs separately before updating them
|
||||
- Archiving work shouldn't be blocked by spec review decisions
|
||||
- Maintains flexibility in the deployment workflow
|
||||
|
||||
2. **Flag Naming Convention**: Chose `--skip-specs` for clarity and consistency:
|
||||
- Clearly indicates the action (skipping) and target (specs)
|
||||
- Follows kebab-case convention for CLI flags
|
||||
- Converts naturally to `skipSpecs` camelCase in code
|
||||
|
||||
3. **Console Messaging Strategy**: Added explicit messages for all spec-skipping scenarios:
|
||||
- When flag is used: "Skipping spec updates (--skip-specs flag provided)."
|
||||
- When user declines: "Skipping spec updates. Proceeding with archive."
|
||||
- Ensures users always understand what's happening with their specs
|
||||
|
||||
4. **Test Coverage Approach**: Created separate test cases for:
|
||||
- Flag-based skipping (explicit user choice via CLI)
|
||||
- Interactive declining (runtime user decision)
|
||||
- Both verify the same outcome but test different code paths
|
||||
|
||||
### Use Cases Addressed
|
||||
|
||||
- **Infrastructure Changes**: Changes to build tools, CI/CD, dependencies
|
||||
- **Documentation Updates**: README updates, comment improvements
|
||||
- **Tooling Modifications**: Developer tools, scripts, configuration files
|
||||
- **Refactoring**: Code improvements that don't change functionality/specs
|
||||
|
||||
### Future Considerations
|
||||
|
||||
- Could potentially auto-detect when changes don't include specs and suggest using the flag
|
||||
- May want to track which archives skipped spec updates for audit purposes
|
||||
@@ -0,0 +1,45 @@
|
||||
# Design: Spec Commands
|
||||
|
||||
## Architecture Decisions
|
||||
|
||||
### Command Hierarchy
|
||||
We chose a subcommand pattern (`spec show`, `spec list`, `spec validate`) to:
|
||||
- Group related functionality under a common namespace
|
||||
- Enable future extensibility without polluting the top-level CLI
|
||||
- Maintain consistency with the planned `change` command structure
|
||||
|
||||
### JSON Schema Structure
|
||||
The spec JSON schema follows this structure:
|
||||
```typescript
|
||||
{
|
||||
version: string, // Schema version for compatibility
|
||||
format: "spec", // Identifies this as a spec document
|
||||
sourcePath: string, // Original markdown file path
|
||||
id: string, // Spec identifier from filename
|
||||
title: string, // Human-readable title
|
||||
overview?: string, // Optional overview section
|
||||
requirements: Array<{
|
||||
id: string,
|
||||
text: string,
|
||||
scenarios: Array<{
|
||||
id: string,
|
||||
text: string
|
||||
}>
|
||||
}>
|
||||
}
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- Flat structure for requirements array (vs nested objects) for easier iteration
|
||||
- Scenarios nested within requirements to maintain relationship
|
||||
- Metadata fields (version, format, sourcePath) for tooling integration
|
||||
|
||||
### Parser Architecture
|
||||
- **Markdown-first approach**: Parse markdown headings rather than custom syntax
|
||||
- **Streaming parser**: Process line-by-line to handle large files efficiently
|
||||
- **Strict heading hierarchy**: Enforce ##/###/#### structure for consistency
|
||||
|
||||
### Validation Strategy
|
||||
- **Parse-time validation**: Catch structural issues during parsing
|
||||
- **Schema validation**: Use Zod for runtime type checking of parsed data
|
||||
- **Separate validation command**: Allow validation without full parsing/conversion
|
||||
@@ -0,0 +1,19 @@
|
||||
# Change: Add Spec Commands with JSON Output
|
||||
|
||||
## Why
|
||||
|
||||
Currently, OpenSpec specs can only be viewed as markdown files. This makes programmatic access difficult and prevents integration with CI/CD pipelines, external tools, and automated processing.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add new `openspec spec` command with three subcommands: `show`, `list`, and `validate`
|
||||
- Implement JSON output capability for specs using heading-based parsing
|
||||
- Add Zod schemas for spec structure validation
|
||||
- Enable content filtering options (requirements only, no scenarios, specific requirement)
|
||||
|
||||
## Impact
|
||||
|
||||
- **Affected specs**: None (new capability)
|
||||
- **Affected code**:
|
||||
- src/cli/index.ts (register new command)
|
||||
- package.json (add zod dependency)
|
||||
@@ -0,0 +1,43 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Spec Command
|
||||
|
||||
The system SHALL provide a `spec` command with subcommands for displaying, listing, and validating specifications.
|
||||
|
||||
#### Scenario: Show spec as JSON
|
||||
|
||||
- **WHEN** executing `openspec spec show init --json`
|
||||
- **THEN** parse the markdown spec file
|
||||
- **AND** extract headings and content hierarchically
|
||||
- **AND** output valid JSON to stdout
|
||||
|
||||
#### Scenario: List all specs
|
||||
|
||||
- **WHEN** executing `openspec spec list`
|
||||
- **THEN** scan the openspec/specs directory
|
||||
- **AND** return list of all available capabilities
|
||||
- **AND** support JSON output with `--json` flag
|
||||
|
||||
#### Scenario: Filter spec content
|
||||
|
||||
- **WHEN** executing `openspec spec show init --requirements`
|
||||
- **THEN** display only requirement names and SHALL statements
|
||||
- **AND** exclude scenario content
|
||||
|
||||
#### Scenario: Validate spec structure
|
||||
|
||||
- **WHEN** executing `openspec spec validate init`
|
||||
- **THEN** parse the spec file
|
||||
- **AND** validate against Zod schema
|
||||
- **AND** report any structural issues
|
||||
|
||||
### Requirement: JSON Schema Definition
|
||||
|
||||
The system SHALL define Zod schemas that accurately represent the spec structure for runtime validation.
|
||||
|
||||
#### Scenario: Schema validation
|
||||
|
||||
- **WHEN** parsing a spec into JSON
|
||||
- **THEN** validate the structure using Zod schemas
|
||||
- **AND** ensure all required fields are present
|
||||
- **AND** provide clear error messages for validation failures
|
||||
@@ -0,0 +1,22 @@
|
||||
# Implementation Tasks (Phase 3: Builds on add-zod-validation and add-change-commands)
|
||||
|
||||
## 1. Command Implementation
|
||||
- [x] 1.1 Create src/commands/spec.ts
|
||||
- [x] 1.2 Import RequirementSchema, ScenarioSchema, SpecSchema from src/core/schemas/
|
||||
- [x] 1.3 Import markdown parser from src/core/parsers/markdown-parser.ts
|
||||
- [x] 1.4 Import SpecValidator from src/core/validation/validator.ts
|
||||
- [x] 1.5 Import JSON converter from src/core/converters/json-converter.ts
|
||||
- [x] 1.6 Implement show subcommand with JSON output using existing converter
|
||||
- [x] 1.7 Implement list subcommand
|
||||
- [x] 1.8 Implement validate subcommand using existing SpecValidator
|
||||
- [x] 1.9 Add filtering options (--requirements, --no-scenarios, -r)
|
||||
- [x] 1.10 Add --strict mode support (leveraging existing validation infrastructure)
|
||||
- [x] 1.11 Add --json flag for validation reports
|
||||
|
||||
## 2. Integration
|
||||
- [x] 2.1 Register spec command in src/cli/index.ts
|
||||
- [x] 2.2 Add integration tests for all subcommands
|
||||
- [x] 2.3 Test JSON output validation
|
||||
- [x] 2.4 Test filtering options
|
||||
- [x] 2.5 Test validation with strict mode
|
||||
- [x] 2.6 Update CLI help documentation (add 'spec' command to main help, document subcommands: show, list, validate)
|
||||
@@ -0,0 +1,104 @@
|
||||
# Design: Zod Validation Framework
|
||||
|
||||
## Architecture Decisions
|
||||
|
||||
### Validation Levels
|
||||
Three-tier validation system:
|
||||
1. **ERROR**: Structural issues that prevent parsing (must fix)
|
||||
2. **WARNING**: Quality issues that should be addressed (recommended fix)
|
||||
3. **INFO**: Suggestions for improvement (optional)
|
||||
|
||||
**Rationale:**
|
||||
- Gradual enforcement allows teams to adopt validation incrementally
|
||||
- CI/CD can fail on errors but allow warnings initially
|
||||
- Info level provides guidance without blocking
|
||||
|
||||
### Validation Rules Hierarchy
|
||||
|
||||
#### Spec Validation Rules
|
||||
```
|
||||
ERROR level:
|
||||
- Missing ## Overview or ## Requirements sections
|
||||
- Invalid heading hierarchy
|
||||
- Malformed requirement/scenario structure
|
||||
|
||||
WARNING level:
|
||||
- Requirements without scenarios
|
||||
- Requirements missing SHALL keyword
|
||||
- Empty overview section
|
||||
|
||||
INFO level:
|
||||
- Very long requirement text (>500 chars)
|
||||
- Scenarios without Given/When/Then structure
|
||||
```
|
||||
|
||||
#### Change Validation Rules
|
||||
```
|
||||
ERROR level:
|
||||
- Missing ## Why or ## What Changes sections
|
||||
- Invalid delta operation types
|
||||
- Malformed delta structure
|
||||
|
||||
WARNING level:
|
||||
- Why section too brief (<50 chars)
|
||||
- Deltas without clear descriptions
|
||||
- Missing requirements in ADDED/MODIFIED
|
||||
|
||||
INFO level:
|
||||
- Very long why section (>1000 chars)
|
||||
- Too many deltas in single change (>10)
|
||||
```
|
||||
|
||||
### Strict Mode
|
||||
- **Default**: Show all levels, fail on ERROR only
|
||||
- **--strict flag**: Fail on both ERROR and WARNING
|
||||
- **Use case**: Gradual quality improvement in CI/CD pipelines
|
||||
|
||||
### Archive Command Safety
|
||||
**Problem:** Invalid specs could be archived, polluting the archive.
|
||||
|
||||
**Solution:**
|
||||
1. Pre-archive validation (default behavior)
|
||||
2. --no-validate flag with safeguards:
|
||||
- Interactive confirmation prompt
|
||||
- Prominent warning message
|
||||
- Console logging with timestamp
|
||||
- Not recommended for CI/CD usage
|
||||
|
||||
**Rationale:**
|
||||
- Protect archive integrity by default
|
||||
- Allow emergency overrides with accountability
|
||||
- Clear audit trail for validation bypasses
|
||||
|
||||
### Validation Report Format
|
||||
```json
|
||||
{
|
||||
"valid": boolean,
|
||||
"issues": [
|
||||
{
|
||||
"level": "ERROR" | "WARNING" | "INFO",
|
||||
"path": "requirements[0].scenarios",
|
||||
"message": "Requirement must have at least one scenario",
|
||||
"line": 15,
|
||||
"column": 0
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"errors": 2,
|
||||
"warnings": 5,
|
||||
"info": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Machine-readable for tooling integration
|
||||
- Human-friendly messages
|
||||
- Line/column info for IDE integration
|
||||
- Summary for quick assessment
|
||||
|
||||
### Implementation Strategy
|
||||
1. **Zod schemas with refinements**: Built-in validation in type definitions
|
||||
2. **Custom validators**: Additional business logic validation
|
||||
3. **Composable rules**: Mix and match for different contexts
|
||||
4. **Extensible framework**: Easy to add new rules without refactoring
|
||||
@@ -0,0 +1,22 @@
|
||||
# Change: Add Zod Runtime Validation
|
||||
|
||||
## Why
|
||||
|
||||
While the spec and change commands can output JSON, they currently don't perform strict runtime validation beyond basic structure checking. This can lead to invalid specs or changes being processed, silent failures when required fields are missing, and poor error messages.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Enhance existing `spec validate` and `change validate` commands with strict Zod validation
|
||||
- Add validation to the archive command to ensure changes are valid before applying
|
||||
- Add validation to the diff command to ensure changes are well-formed
|
||||
- Provide detailed validation reports in JSON format
|
||||
- Add `--strict` mode that fails on warnings
|
||||
|
||||
## Impact
|
||||
|
||||
- **Affected specs**: cli-spec, cli-change, cli-archive, cli-diff
|
||||
- **Affected code**:
|
||||
- src/commands/spec.ts (enhance validate subcommand)
|
||||
- src/commands/change.ts (enhance validate subcommand)
|
||||
- src/core/archive.ts (add pre-archive validation)
|
||||
- src/core/diff.ts (add validation check)
|
||||
@@ -0,0 +1,18 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Archive Validation
|
||||
|
||||
The archive command SHALL validate changes before applying them to ensure data integrity.
|
||||
|
||||
#### Scenario: Pre-archive validation
|
||||
|
||||
- **WHEN** executing `openspec archive change-name`
|
||||
- **THEN** validate the change structure first
|
||||
- **AND** only proceed if validation passes
|
||||
- **AND** show validation errors if it fails
|
||||
|
||||
#### Scenario: Force archive without validation
|
||||
|
||||
- **WHEN** executing `openspec archive change-name --no-validate`
|
||||
- **THEN** skip validation (unsafe mode)
|
||||
- **AND** show warning about skipping validation
|
||||
@@ -0,0 +1,12 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Diff Command Enhancement
|
||||
|
||||
The diff command SHALL validate change structure before displaying differences.
|
||||
|
||||
#### Scenario: Validate before diff
|
||||
|
||||
- **WHEN** executing `openspec diff change-name`
|
||||
- **THEN** validate change structure
|
||||
- **AND** show validation warnings if present
|
||||
- **AND** continue with diff display
|
||||
@@ -0,0 +1,59 @@
|
||||
# Implementation Tasks (Foundation Phase)
|
||||
|
||||
## 1. Core Schemas
|
||||
- [x] 1.1 Add zod dependency to package.json
|
||||
- [x] 1.2 Create src/core/schemas/base.schema.ts with ScenarioSchema and RequirementSchema
|
||||
- [x] 1.3 Create src/core/schemas/spec.schema.ts with SpecSchema
|
||||
- [x] 1.4 Create src/core/schemas/change.schema.ts with DeltaSchema and ChangeSchema
|
||||
- [x] 1.5 Create src/core/schemas/index.ts to export all schemas
|
||||
|
||||
## 2. Parser Implementation
|
||||
- [x] 2.1 Create src/core/parsers/markdown-parser.ts
|
||||
- [x] 2.2 Implement heading extraction (##, ###, ####)
|
||||
- [x] 2.3 Implement content capture between headings
|
||||
- [x] 2.4 Add tests for parser edge cases
|
||||
|
||||
## 3. Validation Infrastructure
|
||||
- [x] 3.1 Create src/core/validation/types.ts with ValidationLevel, ValidationIssue, ValidationReport types
|
||||
- [x] 3.2 Create src/core/validation/constants.ts with validation rules and thresholds
|
||||
- [x] 3.3 Create src/core/validation/validator.ts with SpecValidator and ChangeValidator classes
|
||||
|
||||
## 4. Enhanced Validation Rules
|
||||
- [x] 4.1 Add RequirementValidation refinements (must have scenarios, must contain SHALL)
|
||||
- [x] 4.2 Add SpecValidation refinements (must have requirements)
|
||||
- [x] 4.3 Add ChangeValidation refinements (must have deltas, why section length)
|
||||
- [x] 4.4 Implement custom error messages for each rule
|
||||
|
||||
## 5. JSON Converter
|
||||
- [x] 5.1 Create src/core/converters/json-converter.ts
|
||||
- [x] 5.2 Implement spec-to-JSON conversion
|
||||
- [x] 5.3 Implement change-to-JSON conversion
|
||||
- [x] 5.4 Add metadata fields (version, format, sourcePath)
|
||||
|
||||
## 6. Archive Command Enhancement
|
||||
- [x] 6.1 Add pre-archive validation check using new validators
|
||||
- [x] 6.2 Add --no-validate flag with required confirmation prompt and warning message: "⚠️ WARNING: Skipping validation may archive invalid specs. Continue? (y/N)"
|
||||
- [x] 6.3 Display validation errors before aborting
|
||||
- [x] 6.4 Log all --no-validate usages to console with timestamp and affected files
|
||||
- [x] 6.5 Add tests for validation scenarios including --no-validate confirmation flow
|
||||
|
||||
## 7. Diff Command Enhancement
|
||||
- [x] 7.1 Add validation check before diff using new validators
|
||||
- [x] 7.2 Show validation warnings (non-blocking)
|
||||
- [x] 7.3 Continue with diff even if warnings present
|
||||
|
||||
## 8. Testing
|
||||
- [x] 8.1 Unit tests for all schemas
|
||||
- [x] 8.2 Unit tests for parser
|
||||
- [x] 8.3 Unit tests for validation rules
|
||||
- [x] 8.4 Integration tests for validation reports
|
||||
- [x] 8.5 Test various invalid spec/change formats
|
||||
- [x] 8.6 Test strict mode behavior
|
||||
- [x] 8.7 Test pre-archive validation
|
||||
- [x] 8.8 Test validation report JSON output
|
||||
|
||||
## 9. Documentation
|
||||
- [x] 9.1 Document schema structure and validation rules (openspec/VALIDATION.md)
|
||||
- [x] 9.2 Update CLI help for archive (document --no-validate flag and its warnings)
|
||||
- [x] 9.3 Update CLI help for diff (document validation warnings behavior)
|
||||
- [x] 9.4 Create migration guide for future command integration (openspec/MIGRATION.md)
|
||||
@@ -0,0 +1,93 @@
|
||||
# Adopt Delta-Based Changes for Specifications
|
||||
|
||||
## Why
|
||||
|
||||
The current approach of storing complete future states in change proposals creates a poor review experience. When reviewing changes on GitHub, reviewers see entire spec files (often 100+ lines) as "added" in green, making it impossible to identify what actually changed. With the recent structured format adoption, we now have clear section boundaries that enable a better approach: storing only additions and modifications.
|
||||
|
||||
## What Changes
|
||||
|
||||
Store only the requirements that actually change, not complete future states:
|
||||
|
||||
- **ADDED Requirements**: New capabilities being introduced
|
||||
- **MODIFIED Requirements**: Existing requirements being changed (must match current header)
|
||||
- **REMOVED Requirements**: Deprecated capabilities
|
||||
- **RENAMED Requirements**: Explicit header changes (e.g., `FROM: Old Name` → `TO: New Name`)
|
||||
|
||||
The archive command will programmatically apply these deltas using normalized header matching (trim leading/trailing whitespace) instead of manually copying entire files.
|
||||
|
||||
## Impact
|
||||
|
||||
**Affected specs**: openspec-conventions, cli-archive, cli-diff
|
||||
|
||||
**Benefits**:
|
||||
- GitHub diffs show only actual changes (25 lines instead of 150+)
|
||||
- Reviewers immediately see what's being added, modified, or removed
|
||||
- Conflicts are more apparent when two changes modify the same requirement
|
||||
- Archive command can programmatically apply changes
|
||||
|
||||
**Format**: Delta format only - all changes must use ADDED/MODIFIED/REMOVED sections.
|
||||
|
||||
## Example
|
||||
|
||||
Instead of storing a 150-line complete future spec, store only:
|
||||
|
||||
```markdown
|
||||
# User Authentication - Changes
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: OAuth Support
|
||||
Users SHALL authenticate via OAuth providers including Google and GitHub.
|
||||
|
||||
#### Scenario: OAuth login flow
|
||||
- **WHEN** user selects OAuth provider
|
||||
- **THEN** redirect to provider authorization
|
||||
- **AND** exchange authorization code for tokens
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Session Management
|
||||
Sessions SHALL expire after 30 minutes of inactivity.
|
||||
|
||||
#### Scenario: Inactive session timeout
|
||||
- **WHEN** no activity for 30 minutes ← (was 60 minutes)
|
||||
- **THEN** invalidate session token
|
||||
- **AND** require re-authentication
|
||||
|
||||
## RENAMED Requirements
|
||||
- FROM: `### Requirement: Basic Authentication`
|
||||
- TO: `### Requirement: Email Authentication`
|
||||
```
|
||||
|
||||
This makes reviews focused and changes explicit.
|
||||
|
||||
## Conflict Resolution
|
||||
|
||||
Git naturally detects conflicts when two changes modify the same requirement header. This is actually better than full-state storage where Git might silently merge incompatible changes.
|
||||
|
||||
## Decisions and Product Guidelines
|
||||
|
||||
To keep the archive flow lean and predictable, the following decisions apply:
|
||||
|
||||
- New spec creation: When a target spec does not exist, auto-generate a minimal skeleton and insert ADDED requirements only. Skeleton format:
|
||||
- `# [Spec Name] Specification`
|
||||
- `## Purpose` with placeholder: "TBD — created by archiving change [change-name]. Update Purpose after archive."
|
||||
- `## Requirements`
|
||||
- If a non-existent spec includes MODIFIED/REMOVED/RENAMED, abort with guidance to create via ADDED-only first.
|
||||
|
||||
- Requirement identification: Match requirements by exact header `### Requirement: [Name]` with trim-only normalization and case-sensitive comparison. Use a requirement-block extractor that preserves the exact header and captures full content (including scenarios) for both main specs and delta files.
|
||||
|
||||
- Application order and atomicity: Apply deltas in order RENAMED → REMOVED → MODIFIED → ADDED. Validate all operations first, apply in-memory, and write each spec once. On any validation failure, abort without writing partial results. An aggregated totals line is displayed across all specs: `Totals: + A, ~ M, - R, → N`.
|
||||
|
||||
- Validation matrix: Enforce that MODIFIED/REMOVED exist; ADDED do not exist; RENAMED FROM exists and TO does not; no duplicates after all operations; and no cross-section conflicts (e.g., same item in MODIFIED and REMOVED). When a rename and modify apply to the same item, MODIFIED must reference the NEW header.
|
||||
|
||||
- Idempotency: Keep v1 simple. Abort on precondition failures (e.g., ADDED already exists) with clear errors. Do not implement no-op detection in v1.
|
||||
|
||||
- Output and UX: For each spec, display operation counts using standard symbols `+ ~ - →`. Optionally include a short aggregated totals line at the end. Keep messages concise and actionable.
|
||||
|
||||
- Error messaging: Standardize messages as `[spec] [operation] failed for header "### Requirement: X" — reason`. On abort, explicitly state: `Aborted. No files were changed.`
|
||||
- Subsections: Any subsections under a requirement (e.g., `#### Scenario: ...`) are preserved verbatim during parsing and application.
|
||||
|
||||
- Backward compatibility: Reject full future-state spec copies for existing specs with guidance to convert to deltas. Allow brand-new specs to be created via ADDED-only deltas using the skeleton above.
|
||||
|
||||
- Dry-run: Deferred for v1 to keep scope minimal.
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
# CLI Archive Command - Changes
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Spec Update Process
|
||||
|
||||
Before moving the change to archive, the command SHALL apply delta changes to main specs to reflect the deployed reality.
|
||||
|
||||
#### Scenario: Applying delta changes
|
||||
|
||||
- **WHEN** archiving a change with delta-based specs
|
||||
- **THEN** parse and apply delta changes as defined in openspec-conventions
|
||||
- **AND** validate all operations before applying
|
||||
|
||||
#### Scenario: Validating delta changes
|
||||
|
||||
- **WHEN** processing delta changes
|
||||
- **THEN** perform validations as specified in openspec-conventions
|
||||
- **AND** if validation fails, show specific errors and abort
|
||||
|
||||
#### Scenario: Conflict detection
|
||||
|
||||
- **WHEN** applying deltas would create duplicate requirement headers
|
||||
- **THEN** abort with error message showing the conflict
|
||||
- **AND** suggest manual resolution
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Display Output
|
||||
|
||||
The command SHALL provide clear feedback about delta operations.
|
||||
|
||||
#### Scenario: Showing delta application
|
||||
|
||||
- **WHEN** applying delta changes
|
||||
- **THEN** display for each spec:
|
||||
- Number of requirements added
|
||||
- Number of requirements modified
|
||||
- Number of requirements removed
|
||||
- Number of requirements renamed
|
||||
- **AND** use standard output symbols (+ ~ - →) as defined in openspec-conventions:
|
||||
```
|
||||
Applying changes to specs/user-auth/spec.md:
|
||||
+ 2 added
|
||||
~ 3 modified
|
||||
- 1 removed
|
||||
→ 1 renamed
|
||||
```
|
||||
@@ -0,0 +1,45 @@
|
||||
# CLI Diff Command - Changes
|
||||
|
||||
## REMOVED Requirements
|
||||
|
||||
### Requirement: Display Format
|
||||
|
||||
The diff command SHALL display unified diff output in text format.
|
||||
|
||||
**Reason for removal**: The standard unified diff format is replaced by requirement-level side-by-side comparison that better shows semantic changes rather than line-by-line text differences.
|
||||
|
||||
#### Scenario: Unified diff output (deprecated)
|
||||
|
||||
- **WHEN** running `openspec diff <change>`
|
||||
- **THEN** show a unified text diff of files
|
||||
- **AND** include `+`/`-` prefixed lines representing additions and removals
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Diff Output
|
||||
|
||||
The command SHALL show a requirement-level comparison displaying only changed requirements.
|
||||
|
||||
#### Scenario: Side-by-side comparison of changes
|
||||
|
||||
- **WHEN** running `openspec diff <change>`
|
||||
- **THEN** display only requirements that have changed
|
||||
- **AND** show them in a side-by-side format that:
|
||||
- Clearly shows the current version on the left
|
||||
- Shows the future version on the right
|
||||
- Indicates new requirements (not in current)
|
||||
- Indicates removed requirements (not in future)
|
||||
- Aligns modified requirements for easy comparison
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Validation
|
||||
|
||||
The command SHALL validate that changes can be applied successfully.
|
||||
|
||||
#### Scenario: Invalid delta references
|
||||
|
||||
- **WHEN** delta references non-existent requirement
|
||||
- **THEN** show error message with specific requirement
|
||||
- **AND** continue showing other valid changes
|
||||
- **AND** clearly mark failed changes in the output
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
# OpenSpec Conventions - Changes
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Header-Based Requirement Identification
|
||||
|
||||
Requirement headers SHALL serve as unique identifiers for programmatic matching between current specs and proposed changes.
|
||||
|
||||
#### Scenario: Matching requirements programmatically
|
||||
|
||||
- **WHEN** processing delta changes
|
||||
- **THEN** use the `### Requirement: [Name]` header as the unique identifier
|
||||
- **AND** match using normalized headers: `normalize(header) = trim(header)`
|
||||
- **AND** compare headers with case-sensitive equality after normalization
|
||||
|
||||
#### Scenario: Handling requirement renames
|
||||
|
||||
- **WHEN** renaming a requirement
|
||||
- **THEN** use a special `## RENAMED Requirements` section
|
||||
- **AND** specify both old and new names explicitly:
|
||||
```markdown
|
||||
## RENAMED Requirements
|
||||
- FROM: `### Requirement: Old Name`
|
||||
- TO: `### Requirement: New Name`
|
||||
```
|
||||
- **AND** if content also changes, include under MODIFIED using the NEW header
|
||||
|
||||
#### Scenario: Validating header uniqueness
|
||||
|
||||
- **WHEN** creating or modifying requirements
|
||||
- **THEN** ensure no duplicate headers exist within a spec
|
||||
- **AND** validation tools SHALL flag duplicate headers as errors
|
||||
|
||||
### Requirement: Change Storage Convention
|
||||
|
||||
Change proposals SHALL store only the additions, modifications, and removals to specifications, not complete future states.
|
||||
|
||||
#### Scenario: Creating change proposals with additions
|
||||
|
||||
- **WHEN** creating a change proposal that adds new requirements
|
||||
- **THEN** include only the new requirements under `## ADDED Requirements`
|
||||
- **AND** each requirement SHALL include its complete content
|
||||
- **AND** use the standard structured format for requirements and scenarios
|
||||
|
||||
#### Scenario: Creating change proposals with modifications
|
||||
|
||||
- **WHEN** creating a change proposal that modifies existing requirements
|
||||
- **THEN** include the modified requirements under `## MODIFIED Requirements`
|
||||
- **AND** use the same header text as in the current spec (normalized)
|
||||
- **AND** include the complete modified requirement (not a diff)
|
||||
- **AND** optionally annotate what changed with inline comments like `← (was X)`
|
||||
|
||||
#### Scenario: Creating change proposals with removals
|
||||
|
||||
- **WHEN** creating a change proposal that removes requirements
|
||||
- **THEN** list them under `## REMOVED Requirements`
|
||||
- **AND** use the normalized header text for identification
|
||||
- **AND** include reason for removal
|
||||
- **AND** document any migration path if applicable
|
||||
|
||||
|
||||
The `changes/[name]/specs/` directory SHALL contain:
|
||||
- Delta files showing only what changes
|
||||
- Sections for ADDED, MODIFIED, REMOVED, and RENAMED requirements
|
||||
- Normalized header matching for requirement identification
|
||||
- Complete requirements using the structured format
|
||||
- Clear indication of change type for each requirement
|
||||
|
||||
#### Scenario: Using standard output symbols
|
||||
|
||||
- **WHEN** displaying delta operations in CLI output
|
||||
- **THEN** use these standard symbols:
|
||||
- `+` for ADDED (green)
|
||||
- `~` for MODIFIED (yellow)
|
||||
- `-` for REMOVED (red)
|
||||
- `→` for RENAMED (cyan)
|
||||
|
||||
### Requirement: Archive Process Enhancement
|
||||
|
||||
The archive process SHALL programmatically apply delta changes to current specifications using header-based matching.
|
||||
|
||||
#### Scenario: Archiving changes with deltas
|
||||
|
||||
- **WHEN** archiving a completed change
|
||||
- **THEN** the archive command SHALL:
|
||||
1. Parse RENAMED sections first and apply renames
|
||||
2. Parse REMOVED sections and remove by normalized header match
|
||||
3. Parse MODIFIED sections and replace by normalized header match (using new names if renamed)
|
||||
4. Parse ADDED sections and append new requirements
|
||||
- **AND** validate that all MODIFIED/REMOVED headers exist in current spec
|
||||
- **AND** validate that ADDED headers don't already exist
|
||||
- **AND** generate the updated spec in the main specs/ directory
|
||||
|
||||
#### Scenario: Handling conflicts during archive
|
||||
|
||||
- **WHEN** delta changes conflict with current spec state
|
||||
- **THEN** the archive command SHALL report specific conflicts
|
||||
- **AND** require manual resolution before proceeding
|
||||
- **AND** provide clear guidance on resolving conflicts
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. Update Conventions
|
||||
- [x] 1.1 Update openspec-conventions spec with delta-based approach
|
||||
- [x] 1.2 Add Header-Based Requirement Identification
|
||||
- [x] 1.3 Define ADDED/MODIFIED/REMOVED/RENAMED sections
|
||||
- [x] 1.4 Document standard output symbols (+ ~ - →)
|
||||
- [x] 1.5 Update openspec/README.md with delta-based conventions
|
||||
- [x] 1.6 Update examples to use delta format
|
||||
|
||||
## 2. Update Diff Command
|
||||
- [ ] 2.1 Update cli-diff spec with requirement-level comparison
|
||||
- [ ] 2.2 Parse specs into requirement-level structures
|
||||
- [ ] 2.3 Apply deltas to generate future state
|
||||
- [ ] 2.4 Implement side-by-side comparison view (changes only)
|
||||
- [ ] 2.5 Add tests for requirement-level comparison
|
||||
- [ ] 2.6 Add tests for side-by-side view formatting
|
||||
|
||||
## 3. Update Archive Command
|
||||
- [x] 3.1 Update cli-archive spec with delta processing behavior
|
||||
- [x] 3.2 Implement requirement-block extractor that preserves exact headers (`### Requirement: [Name]`) and captures full content (including scenarios)
|
||||
- [x] 3.3 Implement normalized header matching (trim-only, case-sensitive)
|
||||
- [x] 3.4 Parse delta sections (ADDED/MODIFIED/REMOVED/RENAMED)
|
||||
- [x] 3.5 New spec creation when target spec does not exist
|
||||
- [x] 3.5.1 Auto-generate minimal skeleton: `# [Spec Name] Specification`, `## Purpose` placeholder, `## Requirements`
|
||||
- [x] 3.5.2 Allow only ADDED operations for non-existent specs; abort if MODIFIED/REMOVED/RENAMED present
|
||||
- [x] 3.6 Apply changes in order: RENAMED → REMOVED → MODIFIED → ADDED
|
||||
- [x] 3.7 Validation and conflict checks
|
||||
- [x] 3.7.1 MODIFIED/REMOVED requirements exist (after applying rename mappings)
|
||||
- [x] 3.7.2 ADDED requirements don't already exist (consider post-rename state)
|
||||
- [x] 3.7.3 RENAMED FROM headers exist; TO headers don't (including collisions with ADDED)
|
||||
- [x] 3.7.4 No duplicate headers within specs after all operations
|
||||
- [x] 3.7.5 Detect cross-section conflicts (e.g., same requirement in MODIFIED and REMOVED)
|
||||
- [x] 3.7.6 When a rename exists, require MODIFIED to reference the NEW header
|
||||
- [x] 3.8 Atomic updates
|
||||
- [x] 3.8.1 Validate all deltas first; stage updates in-memory per spec
|
||||
- [x] 3.8.2 Single write per spec; abort entire archive on any validation failure (no partial writes)
|
||||
- [x] 3.9 Output and error messaging
|
||||
- [x] 3.9.1 Display per-spec operation counts with symbols: `+` added, `~` modified, `-` removed, `→` renamed
|
||||
- [x] 3.9.2 Optionally display an aggregated totals line across all specs
|
||||
- [x] 3.9.3 Standardize error message format: `[spec] [operation] failed for header "### Requirement: X" — reason`; end with `Aborted. No files were changed.` on failure
|
||||
- [x] 3.10 Idempotency behavior (v1): abort on precondition failures (e.g., ADDED already exists); do not implement no-op detection
|
||||
- [x] 3.11 Tests
|
||||
- [x] 3.11.1 Header normalization (trim-only) matching
|
||||
- [x] 3.11.2 Apply in correct order (RENAMED → REMOVED → MODIFIED → ADDED)
|
||||
- [x] 3.11.3 Validation edge cases (missing headers, duplicates, rename collisions, conflicting sections)
|
||||
- [x] 3.11.4 Rename + modify interplay (MODIFIED uses new header)
|
||||
- [x] 3.11.5 New spec creation via skeleton
|
||||
- [x] 3.11.6 Multi-spec mixed operations with independent validation and write
|
||||
|
||||
## Notes
|
||||
- Archive command is critical path - must work reliably
|
||||
- All new changes must use delta format
|
||||
- Header normalization: normalize(header) = trim(header)
|
||||
- Diff command shows only changed requirements in side-by-side comparison
|
||||
@@ -0,0 +1,19 @@
|
||||
# Design: Verb–Noun CLI Structure Adoption
|
||||
|
||||
## Overview
|
||||
We will make verb commands (`list`, `show`, `validate`, `diff`, `archive`) the primary interface and keep noun commands (`spec`, `change`) as deprecated aliases for one release.
|
||||
|
||||
## Decisions
|
||||
|
||||
1. Keep routing centralized in `src/cli/index.ts`.
|
||||
2. Add `--specs`/`--changes` to `openspec list`, with `--changes` as default.
|
||||
3. Show deprecation warnings for `openspec change list` and, more generally, for any `openspec change ...` and `openspec spec ...` subcommands.
|
||||
4. Do not change `show`/`validate` behavior beyond help text; they already support `--type` for disambiguation.
|
||||
|
||||
## Backward Compatibility
|
||||
All noun-based commands continue to work with clear deprecation warnings directing users to verb-first equivalents.
|
||||
|
||||
## Out of Scope
|
||||
JSON output parity for `openspec list` across modes and `show --specs/--changes` discovery are follow-ups.
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# Change: Adopt Verb–Noun CLI Structure (Deprecate Noun-Based Commands)
|
||||
|
||||
## Why
|
||||
|
||||
Most widely used CLIs (git, docker, kubectl) start with an action (verb) followed by the object (noun). This matches how users think: “do X to Y”. Using verbs as top-level commands improves clarity, discoverability, and extensibility.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Promote top-level verb commands as primary entry points: `list`, `show`, `validate`, `diff`, `archive`.
|
||||
- Deprecate noun-based top-level commands: `openspec spec ...` and `openspec change ...`.
|
||||
- Introduce consistent noun scoping via flags where applicable (e.g., `--changes`, `--specs`) and keep smart defaults.
|
||||
- Clarify disambiguation for `show` and `validate` when names collide.
|
||||
|
||||
### Mappings (From → To)
|
||||
|
||||
- **List**
|
||||
- From: `openspec change list`
|
||||
- To: `openspec list --changes` (default), or `openspec list --specs`
|
||||
|
||||
- **Show**
|
||||
- From: `openspec spec show <spec-id>` / `openspec change show <change-id>`
|
||||
- To: `openspec show <item-id>` with auto-detect, use `--type spec|change` if ambiguous
|
||||
|
||||
- **Validate**
|
||||
- From: `openspec spec validate <spec-id>` / `openspec change validate <change-id>`
|
||||
- To: `openspec validate <item-id> --type spec|change`, or bulk: `openspec validate --specs` / `--changes` / `--all`
|
||||
|
||||
### Backward Compatibility
|
||||
|
||||
- Keep `openspec spec` and `openspec change` available with deprecation warnings for one release cycle.
|
||||
- Update help text to point users to the verb–noun alternatives.
|
||||
|
||||
## Impact
|
||||
|
||||
- **Affected specs**:
|
||||
- `cli-list`: Add support for `--specs` and explicit `--changes` (default remains changes)
|
||||
- `openspec-conventions`: Add explicit requirement establishing verb–noun CLI design and deprecation guidance
|
||||
- **Affected code**:
|
||||
- `src/cli/index.ts`: Un-deprecate top-level `list`; mark `change list` as deprecated; ensure help text and warnings align
|
||||
- `src/core/list.ts`: Support listing specs via `--specs` and default to changes; shared output shape
|
||||
- Optional follow-ups: tighten `show`/`validate` help and ambiguity handling
|
||||
|
||||
## Explicit Changes
|
||||
|
||||
**CLI Design**
|
||||
- From: Mixed model with nouns (`spec`, `change`) and some top-level verbs; `openspec list` currently deprecated
|
||||
- To: Verbs as primary: `openspec list|show|validate|diff|archive`; nouns scoped via flags or item ids; noun commands deprecated
|
||||
- Reason: Align with common CLIs; improve UX; simpler mental model
|
||||
- Impact: Non-breaking with deprecation period; users migrate incrementally
|
||||
|
||||
**Listing Behavior**
|
||||
- From: `openspec change list` (primary), `openspec list` (deprecated)
|
||||
- To: `openspec list` as primary, defaulting to `--changes`; add `--specs` to list specs
|
||||
- Reason: Consistent verb–noun style; better discoverability
|
||||
- Impact: New option; preserves existing behavior via default
|
||||
|
||||
## Rollout and Deprecation Policy
|
||||
|
||||
- Show deprecation warnings on noun-based commands for one release.
|
||||
- Document new usage in `openspec/README.md` and CLI help.
|
||||
- After one release, consider removing noun-based commands, or keep as thin aliases without warnings.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Should `show` also accept `--changes`/`--specs` for discovery without an id? (Out of scope here; current auto-detect and `--type` remain.)
|
||||
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
# Delta: CLI List Command
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Command Execution
|
||||
The command SHALL scan and analyze either active changes or specs based on the selected mode.
|
||||
|
||||
#### Scenario: Scanning for changes (default)
|
||||
- **WHEN** `openspec list` is executed without flags
|
||||
- **THEN** scan the `openspec/changes/` directory for change directories
|
||||
- **AND** exclude the `archive/` subdirectory from results
|
||||
- **AND** parse each change's `tasks.md` file to count task completion
|
||||
|
||||
#### Scenario: Scanning for specs
|
||||
- **WHEN** `openspec list --specs` is executed
|
||||
- **THEN** scan the `openspec/specs/` directory for capabilities
|
||||
- **AND** read each capability's `spec.md`
|
||||
- **AND** parse requirements to compute requirement counts
|
||||
|
||||
### Requirement: Output Format
|
||||
The command SHALL display items in a clear, readable table format with mode-appropriate progress or counts.
|
||||
|
||||
#### Scenario: Displaying change list (default)
|
||||
- **WHEN** displaying the list of changes
|
||||
- **THEN** show a table with columns:
|
||||
- Change name (directory name)
|
||||
- Task progress (e.g., "3/5 tasks" or "✓ Complete")
|
||||
|
||||
#### Scenario: Displaying spec list
|
||||
- **WHEN** displaying the list of specs
|
||||
- **THEN** show a table with columns:
|
||||
- Spec id (directory name)
|
||||
- Requirement count (e.g., "requirements 12")
|
||||
|
||||
### Requirement: Empty State
|
||||
The command SHALL provide clear feedback when no items are present for the selected mode.
|
||||
|
||||
#### Scenario: Handling empty state (changes)
|
||||
- **WHEN** no active changes exist (only archive/ or empty changes/)
|
||||
- **THEN** display: "No active changes found."
|
||||
|
||||
#### Scenario: Handling empty state (specs)
|
||||
- **WHEN** no specs directory exists or contains no capabilities
|
||||
- **THEN** display: "No specs found."
|
||||
|
||||
### Requirement: Flags
|
||||
The command SHALL accept flags to select the noun being listed.
|
||||
|
||||
#### Scenario: Selecting specs
|
||||
- **WHEN** `--specs` is provided
|
||||
- **THEN** list specs instead of changes
|
||||
|
||||
#### Scenario: Selecting changes
|
||||
- **WHEN** `--changes` is provided
|
||||
- **THEN** list changes explicitly (same as default behavior)
|
||||
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# Delta: OpenSpec Conventions — Verb–Noun CLI Design
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Verb–Noun CLI Command Structure
|
||||
OpenSpec CLI design SHALL use verbs as top-level commands with nouns provided as arguments or flags for scoping.
|
||||
|
||||
#### Scenario: Verb-first command discovery
|
||||
- **WHEN** a user runs a command like `openspec list`
|
||||
- **THEN** the verb communicates the action clearly
|
||||
- **AND** nouns refine scope via flags or arguments (e.g., `--changes`, `--specs`)
|
||||
|
||||
#### Scenario: Backward compatibility for noun commands
|
||||
- **WHEN** users run noun-prefixed commands such as `openspec spec ...` or `openspec change ...`
|
||||
- **THEN** the CLI SHALL continue to support them for at least one release
|
||||
- **AND** display a deprecation warning that points to verb-first alternatives
|
||||
|
||||
#### Scenario: Disambiguation guidance
|
||||
- **WHEN** item names are ambiguous between changes and specs
|
||||
- **THEN** `openspec show` and `openspec validate` SHALL accept `--type spec|change`
|
||||
- **AND** the help text SHALL document this clearly
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. CLI Behavior and Help
|
||||
- [x] 1.1 Un-deprecate top-level `openspec list`; mark `change list` as deprecated with warning that points to `openspec list`
|
||||
- [x] 1.2 Add support to list specs via `openspec list --specs` and keep `--changes` as default
|
||||
- [x] 1.3 Update command descriptions and `--help` output to emphasize verb–noun pattern
|
||||
- [x] 1.4 Keep `openspec spec ...` and `openspec change ...` commands working but print deprecation notices
|
||||
|
||||
## 2. Core List Logic
|
||||
- [x] 2.1 Extend `src/core/list.ts` to accept a mode: `changes` (default) or `specs`
|
||||
- [x] 2.2 Implement `specs` listing: scan `openspec/specs/*/spec.md`, compute requirement count via parser, format output consistently
|
||||
- [x] 2.3 Share output structure for both modes; preserve current text table; ensure JSON parity in future change
|
||||
|
||||
## 3. Specs and Conventions
|
||||
- [x] 3.1 Update `openspec/specs/cli-list/spec.md` to document `--specs` (and default to changes)
|
||||
- [x] 3.2 Update `openspec/specs/openspec-conventions/spec.md` with a requirement for verb–noun CLI design and deprecation guidance
|
||||
|
||||
## 4. Tests and Docs
|
||||
- [x] 4.1 Update tests: ensure `openspec list` works for changes and specs; keep `change list` tests but assert warning
|
||||
- [ ] 4.2 Update README and any usage docs to show new primary commands
|
||||
- [ ] 4.3 Add migration notes in repo CHANGELOG or README
|
||||
|
||||
## 5. Follow-ups (Optional, not in this change)
|
||||
- [ ] 5.1 Consider `openspec show --specs/--changes` for discovery without ids
|
||||
- [ ] 5.2 Consider JSON output for `openspec list` with `--json` for both modes
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
## Why
|
||||
|
||||
Currently, users must validate changes and specs individually by specifying each ID. This creates friction when:
|
||||
- Teams want to validate all changes/specs before a release
|
||||
- Developers need to ensure consistency across multiple related changes
|
||||
- Users run validation commands without arguments and receive errors instead of helpful guidance
|
||||
- The subcommand structure requires users to know in advance whether they're validating a change or spec
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add new top-level `validate` command with intuitive flags (--all, --changes, --specs)
|
||||
- Enhance existing `change validate` and `spec validate` to support interactive selection (backwards compatibility)
|
||||
- Interactive selection by default when no arguments provided
|
||||
- Support direct item validation: `openspec validate <item>` with automatic type detection
|
||||
|
||||
## Impact
|
||||
|
||||
- New specs to create: cli-validate
|
||||
- Specs to enhance: cli-change, cli-spec (for backwards compatibility)
|
||||
- Affected code: src/cli/index.ts, src/commands/validate.ts (new), src/commands/spec.ts, src/commands/change.ts
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
# CLI Change Command Spec
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Interactive validation selection
|
||||
|
||||
The change validate command SHALL support interactive selection when no change name is provided.
|
||||
|
||||
#### Scenario: Interactive change selection for validation
|
||||
|
||||
- **WHEN** executing `openspec change validate` without arguments
|
||||
- **THEN** display an interactive list of available changes
|
||||
- **AND** allow the user to select a change to validate
|
||||
- **AND** validate the selected change
|
||||
|
||||
#### Scenario: Non-interactive fallback keeps current behavior
|
||||
|
||||
- **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0`
|
||||
- **WHEN** executing `openspec change validate` without a change name
|
||||
- **THEN** do not prompt interactively
|
||||
- **AND** print the existing hint including available change IDs
|
||||
- **AND** set `process.exitCode = 1`
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# CLI Spec Command Spec
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Interactive spec validation
|
||||
|
||||
The spec validate command SHALL support interactive selection when no spec-id is provided.
|
||||
|
||||
#### Scenario: Interactive spec selection for validation
|
||||
|
||||
- **WHEN** executing `openspec spec validate` without arguments
|
||||
- **THEN** display an interactive list of available specs
|
||||
- **AND** allow the user to select a spec to validate
|
||||
- **AND** validate the selected spec
|
||||
- **AND** maintain all existing validation options (--strict, --json)
|
||||
|
||||
#### Scenario: Non-interactive fallback keeps current behavior
|
||||
|
||||
- **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0`
|
||||
- **WHEN** executing `openspec spec validate` without a spec-id
|
||||
- **THEN** do not prompt interactively
|
||||
- **AND** print the existing error message for missing spec-id
|
||||
- **AND** set non-zero exit code
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
# CLI Validate Command Spec
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Top-level validate command
|
||||
|
||||
The CLI SHALL provide a top-level `validate` command for validating changes and specs with flexible selection options.
|
||||
|
||||
#### Scenario: Interactive validation selection
|
||||
|
||||
- **WHEN** executing `openspec validate` without arguments
|
||||
- **THEN** prompt user to select what to validate (all, changes, specs, or specific item)
|
||||
- **AND** perform validation based on selection
|
||||
- **AND** display results with appropriate formatting
|
||||
|
||||
#### Scenario: Non-interactive environments do not prompt
|
||||
|
||||
- **GIVEN** stdin is not a TTY or `--no-interactive` is provided or environment variable `OPEN_SPEC_INTERACTIVE=0`
|
||||
- **WHEN** executing `openspec validate` without arguments
|
||||
- **THEN** do not prompt interactively
|
||||
- **AND** print a helpful hint listing available commands/flags and exit with code 1
|
||||
|
||||
#### Scenario: Direct item validation
|
||||
|
||||
- **WHEN** executing `openspec validate <item-name>`
|
||||
- **THEN** automatically detect if item is a change or spec
|
||||
- **AND** validate the specified item
|
||||
- **AND** display validation results
|
||||
|
||||
### Requirement: Bulk and filtered validation
|
||||
|
||||
The validate command SHALL support flags for bulk validation (--all) and filtered validation by type (--changes, --specs).
|
||||
|
||||
#### Scenario: Validate everything
|
||||
|
||||
- **WHEN** executing `openspec validate --all`
|
||||
- **THEN** validate all changes in openspec/changes/ (excluding archive)
|
||||
- **AND** validate all specs in openspec/specs/
|
||||
- **AND** display a summary showing passed/failed items
|
||||
- **AND** exit with code 1 if any validation fails
|
||||
|
||||
#### Scenario: Scope of bulk validation
|
||||
|
||||
- **WHEN** validating with `--all` or `--changes`
|
||||
- **THEN** include all change proposals under `openspec/changes/`
|
||||
- **AND** exclude the `openspec/changes/archive/` directory
|
||||
|
||||
- **WHEN** validating with `--specs`
|
||||
- **THEN** include all specs that have a `spec.md` under `openspec/specs/<id>/spec.md`
|
||||
|
||||
#### Scenario: Validate all changes
|
||||
|
||||
- **WHEN** executing `openspec validate --changes`
|
||||
- **THEN** validate all changes in openspec/changes/ (excluding archive)
|
||||
- **AND** display results for each change
|
||||
- **AND** show summary statistics
|
||||
|
||||
#### Scenario: Validate all specs
|
||||
|
||||
- **WHEN** executing `openspec validate --specs`
|
||||
- **THEN** validate all specs in openspec/specs/
|
||||
- **AND** display results for each spec
|
||||
- **AND** show summary statistics
|
||||
|
||||
### Requirement: Validation options and progress indication
|
||||
|
||||
The validate command SHALL support standard validation options (--strict, --json) and display progress during bulk operations.
|
||||
|
||||
#### Scenario: Strict validation
|
||||
|
||||
- **WHEN** executing `openspec validate --all --strict`
|
||||
- **THEN** apply strict validation to all items
|
||||
- **AND** treat warnings as errors
|
||||
- **AND** fail if any item has warnings or errors
|
||||
|
||||
#### Scenario: JSON output
|
||||
|
||||
- **WHEN** executing `openspec validate --all --json`
|
||||
- **THEN** output validation results as JSON
|
||||
- **AND** include detailed issues for each item
|
||||
- **AND** include summary statistics
|
||||
|
||||
#### Scenario: JSON output schema for bulk validation
|
||||
|
||||
- **WHEN** executing `openspec validate --all --json` (or `--changes` / `--specs`)
|
||||
- **THEN** output a JSON object with the following shape:
|
||||
- `items`: Array of objects with fields `{ id: string, type: "change"|"spec", valid: boolean, issues: Issue[], durationMs: number }`
|
||||
- `summary`: Object `{ totals: { items: number, passed: number, failed: number }, byType: { change?: { items: number, passed: number, failed: number }, spec?: { items: number, passed: number, failed: number } } }`
|
||||
- `version`: String identifier for the schema (e.g., `"1.0"`)
|
||||
- **AND** exit with code 1 if any `items[].valid === false`
|
||||
|
||||
Where `Issue` follows the existing per-item validation report shape `{ level: "ERROR"|"WARNING"|"INFO", path: string, message: string }`.
|
||||
|
||||
#### Scenario: Show validation progress
|
||||
|
||||
- **WHEN** validating multiple items (--all, --changes, or --specs)
|
||||
- **THEN** show progress indicator or status updates
|
||||
- **AND** indicate which item is currently being validated
|
||||
- **AND** display running count of passed/failed items
|
||||
|
||||
#### Scenario: Concurrency limits for performance
|
||||
|
||||
- **WHEN** validating multiple items
|
||||
- **THEN** run validations with a bounded concurrency (e.g., 4–8 in parallel)
|
||||
- **AND** ensure progress indicators remain responsive
|
||||
|
||||
### Requirement: Item type detection and ambiguity handling
|
||||
|
||||
The validate command SHALL handle ambiguous names and explicit type overrides to ensure clear, deterministic behavior.
|
||||
|
||||
#### Scenario: Direct item validation with automatic type detection
|
||||
|
||||
- **WHEN** executing `openspec validate <item-name>`
|
||||
- **THEN** if `<item-name>` uniquely matches a change or a spec, validate that item
|
||||
|
||||
#### Scenario: Ambiguity between change and spec names
|
||||
|
||||
- **GIVEN** `<item-name>` exists both as a change and as a spec
|
||||
- **WHEN** executing `openspec validate <item-name>`
|
||||
- **THEN** print an ambiguity error explaining both matches
|
||||
- **AND** suggest passing `--type change` or `--type spec`, or using `openspec change validate` / `openspec spec validate`
|
||||
- **AND** exit with code 1 without performing validation
|
||||
|
||||
#### Scenario: Unknown item name
|
||||
|
||||
- **WHEN** the `<item-name>` matches neither a change nor a spec
|
||||
- **THEN** print a not-found error
|
||||
- **AND** show nearest-match suggestions when available
|
||||
- **AND** exit with code 1
|
||||
|
||||
#### Scenario: Explicit type override
|
||||
|
||||
- **WHEN** executing `openspec validate --type change <item>`
|
||||
- **THEN** treat `<item>` as a change ID and validate it (skipping auto-detection)
|
||||
|
||||
- **WHEN** executing `openspec validate --type spec <item>`
|
||||
- **THEN** treat `<item>` as a spec ID and validate it (skipping auto-detection)
|
||||
|
||||
### Requirement: Interactivity controls
|
||||
|
||||
- The CLI SHALL respect `--no-interactive` to disable prompts.
|
||||
- The CLI SHALL respect `OPEN_SPEC_INTERACTIVE=0` to disable prompts globally.
|
||||
- Interactive prompts SHALL only be shown when stdin is a TTY and interactivity is not disabled.
|
||||
|
||||
#### Scenario: Disabling prompts via flags or environment
|
||||
|
||||
- **WHEN** `openspec validate` is executed with `--no-interactive` or with environment `OPEN_SPEC_INTERACTIVE=0`
|
||||
- **THEN** the CLI SHALL not display interactive prompts
|
||||
- **AND** SHALL print non-interactive hints or chosen outputs as appropriate
|
||||
@@ -0,0 +1,81 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. Change Command: Interactive Validation Selection
|
||||
- [x] 1.1 Add `--no-interactive` flag to `change validate` in `src/cli/index.ts`
|
||||
- [x] 1.2 Implement interactivity gate respecting TTY and `OPEN_SPEC_INTERACTIVE=0` in `src/commands/change.ts`
|
||||
- [x] 1.3 When no `[change-name]` is provided and interactivity is allowed, prompt with a list of active changes (exclude `archive/`) and validate the selected one
|
||||
- [x] 1.4 Preserve current non-interactive fallback: print available change IDs and hint, set `process.exitCode = 1`
|
||||
- [x] 1.5 Tests: add coverage for interactive and non-interactive flows
|
||||
- Added `test/commands/change.interactive-validate.test.ts`
|
||||
|
||||
## 2. Spec Command: Interactive Validation Selection
|
||||
- [x] 2.1 Make `spec validate` accept optional `[spec-id]` in `src/commands/spec.ts` registration
|
||||
- [x] 2.2 Add `--no-interactive` flag to `spec validate`
|
||||
- [x] 2.3 Implement interactivity gate respecting TTY and `OPEN_SPEC_INTERACTIVE=0`
|
||||
- [x] 2.4 When no `[spec-id]` provided and interactivity allowed, prompt to select from `openspec/specs/*/spec.md` and validate the selected spec
|
||||
- [x] 2.5 Preserve current non-interactive fallback when no spec-id and no interactivity: print existing error and exit code non-zero
|
||||
- [x] 2.6 Tests: add coverage for interactive and non-interactive flows
|
||||
- Added `test/commands/spec.interactive-validate.test.ts`
|
||||
|
||||
## 3. New Top-level `validate` Command
|
||||
- [x] 3.1 Add `validate` command in `src/cli/index.ts`
|
||||
- Options: `--all`, `--changes`, `--specs`, `--type <change|spec>`, `--strict`, `--json`, `--no-interactive`
|
||||
- Usage: `openspec validate [item-name]`
|
||||
- [x] 3.2 Create `src/commands/validate.ts` implementing:
|
||||
- [x] 3.2.1 Interactive selector when no args (choices: All, Changes, Specs, Specific item)
|
||||
- [x] 3.2.2 Non-interactive fallback with helpful hint and exit code 1
|
||||
- [x] 3.2.3 Direct item validation with automatic type detection
|
||||
- [x] 3.2.4 Ambiguity error when name exists as both change and spec; suggest `--type` or subcommands
|
||||
- [x] 3.2.5 Unknown item handling with nearest-match suggestions
|
||||
- [x] 3.2.6 Bulk validation for `--all`, `--changes`, `--specs` (exclude `openspec/changes/archive/`)
|
||||
- [x] 3.2.7 Respect `--strict` and `--json` options; JSON shape per spec
|
||||
- [x] 3.2.8 Exit with code 1 if any validation fails
|
||||
- [x] 3.2.9 Bounded concurrency (default 4–8) for bulk validation
|
||||
- [x] 3.2.10 Progress indication during bulk runs (current item, running counts)
|
||||
|
||||
## 4. Utilities and Shared Helpers
|
||||
- [x] 4.1 Add `src/utils/interactive.ts` with `isInteractive(stdin: NodeJS.ReadStream, noInteractiveFlag?: boolean): boolean`
|
||||
- Considers: `process.stdin.isTTY`, `--no-interactive`, `OPEN_SPEC_INTERACTIVE=0`
|
||||
- [x] 4.2 Add `src/utils/item-discovery.ts` with:
|
||||
- `getActiveChangeIds(root = process.cwd()): Promise<string[]>` (exclude `archive/`)
|
||||
- `getSpecIds(root = process.cwd()): Promise<string[]>` (folders with `spec.md`)
|
||||
- [ ] 4.3 Optional: `src/utils/concurrency.ts` helper for bounded parallelism
|
||||
- [x] 4.4 Reuse `src/core/validation/validator.ts` for item validation
|
||||
|
||||
## 5. JSON Output (Bulk Validation)
|
||||
- [x] 5.1 Implement JSON schema:
|
||||
- `items: Array<{ id: string, type: "change"|"spec", valid: boolean, issues: Issue[], durationMs: number }>`
|
||||
- `summary: { totals: { items: number, passed: number, failed: number }, byType: { change?: { items: number, passed: number, failed: number }, spec?: { items: number, passed: number, failed: number } } }`
|
||||
- `version: "1.0"`
|
||||
- [x] 5.2 Ensure process exit code is 1 if any `items[].valid === false`
|
||||
- [x] 5.3 Tests for JSON shape (keys, types, counts) and exit code behavior
|
||||
- Added `test/commands/validate.test.ts`
|
||||
|
||||
## 6. Progress and UX
|
||||
- [x] 6.1 Use `ora` or minimal console progress to show current item and running counts
|
||||
- [x] 6.2 Keep output stable in `--json` mode (no extra logs to stdout; use stderr for progress if needed)
|
||||
- [x] 6.3 Ensure responsiveness with concurrency limits
|
||||
|
||||
## 7. Tests
|
||||
- [x] 7.1 Add top-level validate tests: `test/commands/validate.test.ts`
|
||||
- Includes non-interactive hint, --all JSON, --specs with concurrency, ambiguity error
|
||||
- [ ] 7.2 Add unit tests for `isInteractive` and item discovery helpers
|
||||
- [x] 7.3 Extend existing change/spec command tests to cover interactive `validate`
|
||||
- Added `test/commands/change.interactive-validate.test.ts`, `test/commands/spec.interactive-validate.test.ts`
|
||||
|
||||
## 8. CLI Help and Docs
|
||||
- [x] 8.1 Update command descriptions/options in `src/cli/index.ts`
|
||||
- [x] 8.2 Verify help output includes `validate` command and flags
|
||||
- [x] 8.3 Ensure existing specs under `openspec/changes/bulk-validation-interactive-selection/specs/*` remain satisfied
|
||||
|
||||
## 9. Non-functional
|
||||
- [x] 9.1 Code style and types: explicit types for exported APIs; avoid `any`
|
||||
- [x] 9.2 No linter errors; stable formatting; avoid unrelated refactors
|
||||
- [x] 9.3 Maintain existing behavior for unaffected commands
|
||||
|
||||
## 10. Acceptance Criteria Mapping
|
||||
- [x] AC-1: `openspec change validate` interactive selection when no arg (TTY only; respects `--no-interactive`/env) — matches cli-change spec
|
||||
- [x] AC-2: `openspec spec validate` interactive selection when no arg (TTY only; respects `--no-interactive`/env) — matches cli-spec spec
|
||||
- [x] AC-3: New `openspec validate` supports interactive selection, bulk/filtered validation, JSON schema, progress, concurrency, exit codes — matches cli-validate spec
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# Fix Update Command Tool Selection
|
||||
|
||||
## Problem
|
||||
|
||||
The `openspec update` command currently forces the creation/update of CLAUDE.md regardless of which AI tool was selected during initialization. This violates the tool-agnostic design principle and creates confusion for users who selected different AI assistants.
|
||||
|
||||
Additionally, different team members may use different AI tools, so we cannot rely on a shared configuration file.
|
||||
|
||||
## Solution
|
||||
|
||||
Modify the update command to:
|
||||
1. Only update AI tool configuration files that already exist
|
||||
2. Never create new AI tool configuration files
|
||||
3. Always update the core OpenSpec files (README.md, etc.)
|
||||
|
||||
## Implementation
|
||||
|
||||
- Remove hardcoded CLAUDE.md update from update command
|
||||
- Implement file existence check before updating any AI tool config
|
||||
- Update each existing AI tool config file with its appropriate markers
|
||||
- No configuration file needed (avoids team conflicts)
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- Update command only modifies existing AI tool configuration files
|
||||
- No new AI tool files created during update
|
||||
- Team members can use different AI tools without conflicts
|
||||
- Existing projects continue to work (backward compatibility)
|
||||
|
||||
## Why
|
||||
|
||||
Users need predictable, tool-agnostic behavior from `openspec update`. Creating or forcing updates for AI tool files that a project does not use causes confusion and merge conflicts. Restricting updates to existing files and always updating core OpenSpec files keeps the workflow consistent for mixed-tool teams.
|
||||
|
||||
## What Changes
|
||||
|
||||
- **cli-update:** Modify update behavior to update only existing AI tool configuration files and never create new ones; always update core OpenSpec files and display an ASCII-safe success message.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
Removed from proposal to follow conventions. See `specs/cli-update/spec.md` for the delta requirements content.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Tool-Agnostic Updates
|
||||
|
||||
The update command SHALL update only existing AI tool configuration files and SHALL NOT create new ones.
|
||||
|
||||
#### Scenario: Updating existing tool files
|
||||
|
||||
- **WHEN** a user runs `openspec update`
|
||||
- **THEN** update each AI tool configuration file that exists (e.g., CLAUDE.md, COPILOT.md)
|
||||
- **AND** do not create missing tool configuration files
|
||||
- **AND** preserve user content outside OpenSpec markers
|
||||
|
||||
### Requirement: Core Files Always Updated
|
||||
|
||||
The update command SHALL always update the core OpenSpec files and display an ASCII-safe success message.
|
||||
|
||||
#### Scenario: Successful update
|
||||
|
||||
- **WHEN** the update completes successfully
|
||||
- **THEN** replace `openspec/README.md` with the latest template
|
||||
- **AND** update existing AI tool configuration files within markers
|
||||
- **AND** display the message: "Updated OpenSpec instructions"
|
||||
@@ -0,0 +1,21 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. Update Update Command
|
||||
- [x] Remove hardcoded CLAUDE.md update from `src/core/update.ts`
|
||||
- [x] Add logic to check for existing AI tool configuration files
|
||||
- [x] Update only existing files using their appropriate configurators
|
||||
- [x] Iterate through all registered configurators to check for existing files
|
||||
|
||||
## 2. Update Configurator Registry
|
||||
- [x] Add method to get all configurators for update command
|
||||
- [x] Ensure each configurator can check if its file exists
|
||||
|
||||
## 3. Add Tests
|
||||
- [x] Test update command with only CLAUDE.md present
|
||||
- [x] Test update command with no AI tool files present
|
||||
- [x] Test update command with multiple AI tool files present
|
||||
- [x] Test that update never creates new AI tool files
|
||||
|
||||
## 4. Update Documentation
|
||||
- [x] Update README to clarify team-friendly behavior
|
||||
- [x] Document that update only modifies existing files
|
||||
@@ -0,0 +1,25 @@
|
||||
# improve-validate-error-messages
|
||||
|
||||
## Why
|
||||
|
||||
Developers struggle to resolve validation failures because current errors lack actionable guidance. Common issues include: missing deltas, missing required sections, and misformatted scenarios that are silently ignored. Without clear remediation steps, users cannot quickly correct structure or formatting, leading to frustration and rework. Improving error messages with concrete fixes, file/section hints, and suggested commands will significantly reduce time-to-green and make OpenSpec more approachable.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Validation errors SHALL include specific remediation steps (what to change and where).
|
||||
- "No deltas found" error SHALL guide users to create `specs/` with proper delta headers and suggest debug commands.
|
||||
- Missing required sections (Spec: Purpose/Requirements; Change: Why/What Changes) SHALL include expected header names and a minimal skeleton example.
|
||||
- Likely misformatted scenarios (bulleted WHEN/THEN/AND) SHALL emit a targeted warning explaining the `#### Scenario:` format and show a conversion template.
|
||||
- All reported issues SHALL include the source file path and structured location (e.g., `deltas[0].requirements[0]`).
|
||||
- Non-JSON output SHOULD end with a short "Next steps" footer when invalid.
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected CLI: validate
|
||||
- Affected code:
|
||||
- `src/commands/validate.ts`
|
||||
- `src/core/validation/validator.ts`
|
||||
- `src/core/validation/constants.ts`
|
||||
- `src/core/parsers/*` (wrapping thrown errors with richer context)
|
||||
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
# Validate Command
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Validation SHALL provide actionable remediation steps
|
||||
Validation output SHALL include specific guidance to fix each error, including expected structure, example headers, and suggested commands to verify fixes.
|
||||
|
||||
#### Scenario: No deltas found in change
|
||||
- **WHEN** validating a change with zero parsed deltas
|
||||
- **THEN** show error "No deltas found" with guidance:
|
||||
- Ensure `openspec/changes/{id}/specs/` exists with `.md` files
|
||||
- Use delta headers: `## ADDED Requirements`, `## MODIFIED Requirements`, `## REMOVED Requirements`, `## RENAMED Requirements`
|
||||
- Each requirement must include at least one `#### Scenario:` block
|
||||
- Try: `openspec change show {id} --json --deltas-only` to inspect what was parsed
|
||||
|
||||
#### Scenario: Missing required sections
|
||||
- **WHEN** a required section is missing
|
||||
- **THEN** the validator SHALL include expected header names and a minimal skeleton:
|
||||
- For Spec: `## Purpose`, `## Requirements`
|
||||
- For Change: `## Why`, `## What Changes`
|
||||
- Show an example snippet of the missing section
|
||||
|
||||
### Requirement: Validator SHALL detect likely misformatted scenarios and warn with a fix
|
||||
The validator SHALL recognize bulleted lines that look like scenarios (e.g., lines beginning with WHEN/THEN/AND) and emit a targeted warning with a conversion example to `#### Scenario:`.
|
||||
|
||||
#### Scenario: Bulleted WHEN/THEN under a Requirement
|
||||
- **WHEN** bullets that start with WHEN/THEN/AND are found under a requirement without any `#### Scenario:` headers
|
||||
- **THEN** emit warning: "Scenarios must use '#### Scenario:' headers", and show a conversion template:
|
||||
```
|
||||
#### Scenario: Short name
|
||||
- **WHEN** ...
|
||||
- **THEN** ...
|
||||
- **AND** ...
|
||||
```
|
||||
|
||||
### Requirement: All issues SHALL include file paths and structured locations
|
||||
Error, warning, and info messages SHALL include:
|
||||
- Source file path (`openspec/changes/{id}/proposal.md`, `.../specs/{cap}/spec.md`)
|
||||
- Structured path (e.g., `deltas[0].requirements[0].scenarios`)
|
||||
|
||||
#### Scenario: Zod validation error
|
||||
- **WHEN** a schema validation fails
|
||||
- **THEN** the message SHALL include `file`, `path`, and a remediation hint if applicable
|
||||
|
||||
### Requirement: Invalid results SHALL include a Next steps footer in human-readable output
|
||||
The CLI SHALL append a Next steps footer when the item is invalid and not using `--json`, including:
|
||||
- Summary line with counts
|
||||
- Top-3 guidance bullets (contextual to the most frequent or blocking errors)
|
||||
- A suggestion to re-run with `--json` and/or the debug command
|
||||
|
||||
#### Scenario: Change invalid summary
|
||||
- **WHEN** a change validation fails
|
||||
- **THEN** print "Next steps" with 2-3 targeted bullets and suggest `openspec change show <id> --json --deltas-only`
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
## 1. Enhance validation messages
|
||||
- [x] 1.1 Add remediation guidance for "No deltas found"
|
||||
- [x] 1.2 Include file path and structured path in all issues
|
||||
- [x] 1.3 Improve messages for missing required sections (Spec, Change)
|
||||
- [x] 1.4 Detect likely misformatted scenarios and warn with conversion example
|
||||
- [x] 1.5 Add "Next steps" footer for non-JSON invalid output
|
||||
|
||||
## 2. Update constants and helpers
|
||||
- [x] 2.1 Centralize guidance snippets in `VALIDATION_MESSAGES`
|
||||
- [x] 2.2 Provide minimal skeleton examples for missing sections
|
||||
|
||||
## 3. Parser integration
|
||||
- [x] 3.1 Capture parser-thrown errors and wrap with richer context
|
||||
- [x] 3.2 Add file/section references to surfaced parser errors
|
||||
|
||||
## 4. Tests
|
||||
- [x] 4.1 Unit tests for validator message composition
|
||||
- [x] 4.2 CLI integration tests for human-readable output (with footer)
|
||||
- [x] 4.3 JSON mode tests (structure unchanged, content enriched)
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
## Why
|
||||
|
||||
OpenSpec specifications lack a consistent structure that makes sections visually identifiable and programmatically parseable across different specs. This makes it harder to maintain consistency and build tooling.
|
||||
|
||||
## What Changes
|
||||
|
||||
**Specification Format Section**
|
||||
- From: No formal structure requirements for specifications
|
||||
- To: Structured format with `### Requirement:` and `#### Scenario:` headers
|
||||
- Reason: Visual consistency and parseability across all specs
|
||||
- Impact: Non-breaking - existing specs can migrate gradually
|
||||
|
||||
**Keyword Formatting**
|
||||
- From: Inconsistent use of WHEN/THEN/AND keywords
|
||||
- To: Bold keywords (**WHEN**, **THEN**, **AND**) in scenario bullets
|
||||
- Reason: Improved readability and consistent visual hierarchy
|
||||
- Impact: Non-breaking - formatting enhancement only
|
||||
|
||||
**Format Flexibility**
|
||||
- From: Implicit understanding that different content needs different formats
|
||||
- To: Explicit allowance for alternative formats (OpenAPI, JSON Schema, etc.)
|
||||
- Reason: Address concern that not all specs fit requirement/scenario pattern
|
||||
- Impact: Non-breaking - clarifies existing practice
|
||||
|
||||
**Migration Guidelines**
|
||||
- From: No migration guidance
|
||||
- To: Documented gradual migration approach
|
||||
- Reason: Allows incremental adoption without disrupting existing specs
|
||||
- Impact: Non-breaking - opt-in migration as specs are modified
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: openspec-conventions (enhancement to existing capability)
|
||||
- Affected code: None initially - this is a documentation standard enhancement
|
||||
- Migration: Gradual - existing specs migrate as they're modified
|
||||
- Tooling: Enables future parsing tools but doesn't require them
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
# OpenSpec Conventions Specification
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Structured Format Adoption
|
||||
|
||||
Behavioral specifications SHALL adopt the structured format with `### Requirement:` and `#### Scenario:` headers as the default.
|
||||
|
||||
#### Scenario: Use structured headings for behavior
|
||||
|
||||
- **WHEN** documenting behavioral requirements
|
||||
- **THEN** use `### Requirement:` for requirements
|
||||
- **AND** use `#### Scenario:` for scenarios with bold WHEN/THEN/AND keywords
|
||||
|
||||
## Purpose
|
||||
|
||||
OpenSpec conventions SHALL define how system capabilities are documented, how changes are proposed and tracked, and how specifications evolve over time. This meta-specification serves as the source of truth for OpenSpec's own conventions.
|
||||
|
||||
## Core Principles
|
||||
|
||||
The system SHALL follow these principles:
|
||||
- Specs reflect what IS currently built and deployed
|
||||
- Changes contain proposals for what SHOULD be changed
|
||||
- AI drives the documentation process
|
||||
- Specs are living documentation kept in sync with deployed code
|
||||
|
||||
## Directory Structure
|
||||
|
||||
WHEN an OpenSpec project is initialized
|
||||
THEN it SHALL have this structure:
|
||||
```
|
||||
openspec/
|
||||
├── project.md # Project-specific context
|
||||
├── README.md # AI assistant instructions
|
||||
├── specs/ # Current deployed capabilities
|
||||
│ └── [capability]/ # Single, focused capability
|
||||
│ ├── spec.md # WHAT and WHY
|
||||
│ └── design.md # HOW (optional, for established patterns)
|
||||
└── changes/ # Proposed changes
|
||||
├── [change-name]/ # Descriptive change identifier
|
||||
│ ├── proposal.md # Why, what, and impact
|
||||
│ ├── tasks.md # Implementation checklist
|
||||
│ ├── design.md # Technical decisions (optional)
|
||||
│ └── specs/ # Complete future state
|
||||
│ └── [capability]/
|
||||
│ └── spec.md # Clean markdown (no diff syntax)
|
||||
└── archive/ # Completed changes
|
||||
└── YYYY-MM-DD-[name]/
|
||||
```
|
||||
|
||||
## Specification Format
|
||||
|
||||
### Requirement: Structured Format for Behavioral Specs
|
||||
|
||||
Behavioral specifications SHALL use a structured format with consistent section headers and keywords to ensure visual consistency and parseability.
|
||||
|
||||
#### Scenario: Writing requirement sections
|
||||
|
||||
- **WHEN** documenting a requirement in a behavioral specification
|
||||
- **THEN** use a level-3 heading with format `### Requirement: [Name]`
|
||||
- **AND** immediately follow with a SHALL statement describing core behavior
|
||||
- **AND** keep requirement names descriptive and under 50 characters
|
||||
|
||||
#### Scenario: Documenting scenarios
|
||||
|
||||
- **WHEN** documenting specific behaviors or use cases
|
||||
- **THEN** use level-4 headings with format `#### Scenario: [Description]`
|
||||
- **AND** use bullet points with bold keywords for steps:
|
||||
- **GIVEN** for initial state (optional)
|
||||
- **WHEN** for conditions or triggers
|
||||
- **THEN** for expected outcomes
|
||||
- **AND** for additional outcomes or conditions
|
||||
|
||||
#### Scenario: Adding implementation details
|
||||
|
||||
- **WHEN** a step requires additional detail
|
||||
- **THEN** use sub-bullets under the main step
|
||||
- **AND** maintain consistent indentation
|
||||
- Sub-bullets provide examples or specifics
|
||||
- Keep sub-bullets concise
|
||||
|
||||
### Requirement: Format Flexibility
|
||||
|
||||
The structured format SHALL be the default for behavioral specifications, but alternative formats MAY be used when more appropriate for the content type.
|
||||
|
||||
#### Scenario: Documenting API specifications
|
||||
|
||||
- **WHEN** documenting REST API endpoints or GraphQL schemas
|
||||
- **THEN** OpenAPI, GraphQL SDL, or similar formats MAY be used
|
||||
- **AND** the spec SHALL clearly indicate the format being used
|
||||
- **AND** behavioral aspects SHALL still follow the structured format
|
||||
|
||||
#### Scenario: Documenting data schemas
|
||||
|
||||
- **WHEN** documenting data structures, database schemas, or configurations
|
||||
- **THEN** JSON Schema, SQL DDL, or similar formats MAY be used
|
||||
- **AND** include the structured format for behavioral rules and constraints
|
||||
|
||||
#### Scenario: Using simplified format
|
||||
|
||||
- **WHEN** documenting simple capabilities without complex scenarios
|
||||
- **THEN** a simplified WHEN/THEN format without full structure MAY be used
|
||||
- **AND** this should be consistent within the capability
|
||||
|
||||
## Change Storage Convention
|
||||
|
||||
### Future State Storage
|
||||
|
||||
WHEN creating a change proposal
|
||||
THEN store the complete future state of affected specs
|
||||
AND use clean markdown without diff syntax
|
||||
|
||||
The `changes/[name]/specs/` directory SHALL contain:
|
||||
- Complete spec files as they will exist after the change
|
||||
- Clean markdown without `+` or `-` prefixes
|
||||
- All formatting and structure of the final intended state
|
||||
|
||||
### Proposal Format
|
||||
|
||||
WHEN documenting what changes
|
||||
THEN the proposal SHALL explicitly describe each change:
|
||||
|
||||
```markdown
|
||||
**[Section or Behavior Name]**
|
||||
- From: [current state/requirement]
|
||||
- To: [future state/requirement]
|
||||
- Reason: [why this change is needed]
|
||||
- Impact: [breaking/non-breaking, who's affected]
|
||||
```
|
||||
|
||||
This explicit format compensates for not having inline diffs and ensures reviewers understand exactly what will change.
|
||||
|
||||
## Change Lifecycle
|
||||
|
||||
The change process SHALL follow these states:
|
||||
|
||||
1. **Propose**: AI creates change with future state specs and explicit proposal
|
||||
2. **Review**: Humans review proposal and future state
|
||||
3. **Approve**: Change is approved for implementation
|
||||
4. **Implement**: Follow tasks.md checklist (can span multiple PRs)
|
||||
5. **Deploy**: Changes are deployed to production
|
||||
6. **Update**: Specs in `specs/` are updated to match deployed reality
|
||||
7. **Archive**: Change is moved to `archive/YYYY-MM-DD-[name]/`
|
||||
|
||||
## Viewing Changes
|
||||
|
||||
WHEN reviewing proposed changes
|
||||
THEN reviewers can compare using:
|
||||
- GitHub PR diff view when changes are committed
|
||||
- Command line: `diff -u specs/[capability]/spec.md changes/[name]/specs/[capability]/spec.md`
|
||||
- Any visual diff tool comparing current vs future state
|
||||
|
||||
The system relies on tools to generate diffs rather than storing them.
|
||||
|
||||
## Capability Naming
|
||||
|
||||
Capabilities SHALL use:
|
||||
- Verb-noun patterns (e.g., `user-auth`, `payment-capture`)
|
||||
- Hyphenated lowercase names
|
||||
- Singular focus (one responsibility per capability)
|
||||
- No nesting (flat structure under `specs/`)
|
||||
|
||||
## When Changes Require Proposals
|
||||
|
||||
A proposal SHALL be created for:
|
||||
- New features or capabilities
|
||||
- Breaking changes to existing behavior
|
||||
- Architecture or pattern changes
|
||||
- Performance optimizations that change behavior
|
||||
- Security updates affecting access patterns
|
||||
|
||||
A proposal is NOT required for:
|
||||
- Bug fixes restoring intended behavior
|
||||
- Typos or formatting fixes
|
||||
- Non-breaking dependency updates
|
||||
- Adding tests for existing behavior
|
||||
- Documentation clarifications
|
||||
|
||||
## Why This Approach
|
||||
|
||||
Clean future state storage provides:
|
||||
- **Readability**: No diff syntax pollution
|
||||
- **AI-compatibility**: Standard markdown that AI tools understand
|
||||
- **Simplicity**: No special parsing or processing needed
|
||||
- **Tool-agnostic**: Any diff tool can show changes
|
||||
- **Clear intent**: Explicit proposals document reasoning
|
||||
|
||||
The structured format adds:
|
||||
- **Visual Consistency**: Requirement and Scenario prefixes make sections instantly recognizable
|
||||
- **Parseability**: Consistent structure enables tooling and automation
|
||||
- **Flexibility**: Alternative formats supported where appropriate
|
||||
- **Gradual Adoption**: Existing specs can migrate incrementally
|
||||
@@ -0,0 +1,19 @@
|
||||
## 1. Update OpenSpec Conventions Spec
|
||||
|
||||
- [x] 1.1 Add "Specification Format" section to openspec-conventions
|
||||
- [x] 1.2 Document structured format with Requirement/Scenario headers
|
||||
- [x] 1.3 Define bold keyword usage (WHEN/THEN/AND) for scenarios
|
||||
- [x] 1.4 Include examples demonstrating the format within the spec itself
|
||||
|
||||
## 2. Update Documentation
|
||||
|
||||
- [x] 2.1 Update the "Why This Approach" section with structured format benefits
|
||||
- [x] 2.2 Ensure spec follows its own format as a demonstration
|
||||
|
||||
## 3. Update Existing Specs
|
||||
|
||||
- [x] 3.1 Update cli-init spec to use structured format in Behavior section
|
||||
- [x] 3.2 Update cli-list spec to use structured format in Behavior section
|
||||
- [x] 3.3 Update cli-update spec to use structured format in Behavior section
|
||||
- [x] 3.4 Update cli-diff spec to use structured format in Behavior section
|
||||
- [x] 3.5 Update cli-archive spec to use structured format in Behavior section
|
||||
@@ -0,0 +1,38 @@
|
||||
# Change: Add View Dashboard Command
|
||||
|
||||
## Why
|
||||
|
||||
Users need a quick, at-a-glance overview of their OpenSpec project status without running multiple commands. Currently, users must run `openspec list --changes` and `openspec list --specs` separately to understand the project state. A unified dashboard view would improve developer experience and provide immediate insight into project progress.
|
||||
|
||||
## What Changes
|
||||
|
||||
### Added `openspec view` Command
|
||||
|
||||
The new command provides an interactive dashboard displaying:
|
||||
- Summary metrics (total specs, requirements, changes, task progress)
|
||||
- Active changes with visual progress bars
|
||||
- Completed changes
|
||||
- Specifications with requirement counts
|
||||
|
||||
### Specifications Affected
|
||||
|
||||
- **cli-view** (NEW): Complete specification for the view dashboard command
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### File Structure
|
||||
- Created `/src/core/view.ts` implementing the `ViewCommand` class
|
||||
- Registered command in `/src/cli/index.ts`
|
||||
- Reuses existing utilities from `task-progress.ts` and `MarkdownParser`
|
||||
|
||||
### Visual Design
|
||||
- Uses Unicode box drawing characters for borders
|
||||
- Color coding: cyan for specs, yellow for active, green for completed
|
||||
- Progress bars using filled (█) and empty (░) blocks
|
||||
- Clean alignment with proper padding
|
||||
|
||||
### Technical Approach
|
||||
- Async data fetching from changes and specs directories
|
||||
- Parallel processing of specs and changes
|
||||
- Error handling for missing or invalid data
|
||||
- Maintains consistency with existing list command output
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
# CLI View Command - Changes
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Dashboard Display
|
||||
|
||||
The system SHALL provide a `view` command that displays a dashboard overview of specs and changes.
|
||||
|
||||
#### Scenario: Basic dashboard display
|
||||
|
||||
- **WHEN** user runs `openspec view`
|
||||
- **THEN** system displays a formatted dashboard with sections for summary, active changes, completed changes, and specifications
|
||||
|
||||
#### Scenario: No OpenSpec directory
|
||||
|
||||
- **WHEN** user runs `openspec view` in a directory without OpenSpec
|
||||
- **THEN** system displays error message "✗ No openspec directory found"
|
||||
|
||||
### Requirement: Summary Section
|
||||
|
||||
The dashboard SHALL display a summary section with key project metrics.
|
||||
|
||||
#### Scenario: Complete summary display
|
||||
|
||||
- **WHEN** dashboard is rendered with specs and changes
|
||||
- **THEN** system shows total number of specifications and requirements
|
||||
- **AND** shows number of active changes in progress
|
||||
- **AND** shows number of completed changes
|
||||
- **AND** shows overall task progress percentage
|
||||
|
||||
#### Scenario: Empty project summary
|
||||
|
||||
- **WHEN** no specs or changes exist
|
||||
- **THEN** summary shows zero counts for all metrics
|
||||
|
||||
### Requirement: Active Changes Display
|
||||
|
||||
The dashboard SHALL show active changes with visual progress indicators.
|
||||
|
||||
#### Scenario: Active changes with progress bars
|
||||
|
||||
- **WHEN** there are in-progress changes with tasks
|
||||
- **THEN** system displays each change with change name left-aligned
|
||||
- **AND** visual progress bar using Unicode characters
|
||||
- **AND** percentage completion on the right
|
||||
|
||||
#### Scenario: No active changes
|
||||
|
||||
- **WHEN** all changes are completed or no changes exist
|
||||
- **THEN** active changes section is omitted from display
|
||||
|
||||
### Requirement: Completed Changes Display
|
||||
|
||||
The dashboard SHALL list completed changes in a separate section.
|
||||
|
||||
#### Scenario: Completed changes listing
|
||||
|
||||
- **WHEN** there are completed changes (all tasks done)
|
||||
- **THEN** system shows them with checkmark indicators in a dedicated section
|
||||
|
||||
#### Scenario: Mixed completion states
|
||||
|
||||
- **WHEN** some changes are complete and others active
|
||||
- **THEN** system separates them into appropriate sections
|
||||
|
||||
### Requirement: Specifications Display
|
||||
|
||||
The dashboard SHALL display specifications sorted by requirement count.
|
||||
|
||||
#### Scenario: Specs listing with counts
|
||||
|
||||
- **WHEN** specifications exist in the project
|
||||
- **THEN** system shows specs sorted by requirement count (descending) with count labels
|
||||
|
||||
#### Scenario: Specs with parsing errors
|
||||
|
||||
- **WHEN** a spec file cannot be parsed
|
||||
- **THEN** system includes it with 0 requirement count
|
||||
|
||||
### Requirement: Visual Formatting
|
||||
|
||||
The dashboard SHALL use consistent visual formatting with colors and symbols.
|
||||
|
||||
#### Scenario: Color coding
|
||||
|
||||
- **WHEN** dashboard elements are displayed
|
||||
- **THEN** system uses cyan for specification items
|
||||
- **AND** yellow for active changes
|
||||
- **AND** green for completed items
|
||||
- **AND** dim gray for supplementary text
|
||||
|
||||
#### Scenario: Progress bar rendering
|
||||
|
||||
- **WHEN** displaying progress bars
|
||||
- **THEN** system uses filled blocks (█) for completed portions and light blocks (░) for remaining
|
||||
|
||||
### Requirement: Error Handling
|
||||
|
||||
The view command SHALL handle errors gracefully.
|
||||
|
||||
#### Scenario: File system errors
|
||||
|
||||
- **WHEN** file system operations fail
|
||||
- **THEN** system continues with available data and omits inaccessible items
|
||||
|
||||
#### Scenario: Invalid data structures
|
||||
|
||||
- **WHEN** specs or changes have invalid format
|
||||
- **THEN** system skips invalid items and continues rendering
|
||||
@@ -0,0 +1,47 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## Design Phase
|
||||
- [x] Research existing list command implementation
|
||||
- [x] Design dashboard layout and information architecture
|
||||
- [x] Choose appropriate command verb (`view`)
|
||||
- [x] Define visual elements (progress bars, colors, layout)
|
||||
|
||||
## Core Implementation
|
||||
- [x] Create ViewCommand class in `/src/core/view.ts`
|
||||
- [x] Implement getChangesData method for fetching change information
|
||||
- [x] Implement getSpecsData method for fetching spec information
|
||||
- [x] Implement displaySummary method for summary metrics
|
||||
- [x] Add progress bar visualization with Unicode characters
|
||||
- [x] Implement color coding using chalk
|
||||
|
||||
## Integration
|
||||
- [x] Import ViewCommand in CLI index
|
||||
- [x] Register `openspec view` command with commander
|
||||
- [x] Add proper error handling and ora spinner integration
|
||||
- [x] Ensure command appears in help documentation
|
||||
|
||||
## Data Processing
|
||||
- [x] Reuse TaskProgress utilities for change progress
|
||||
- [x] Integrate MarkdownParser for spec requirement counting
|
||||
- [x] Handle async operations for file system access
|
||||
- [x] Sort specifications by requirement count
|
||||
|
||||
## Testing and Validation
|
||||
- [x] Build project successfully with new command
|
||||
- [x] Test command with sample data
|
||||
- [x] Verify correct requirement counts match list --specs
|
||||
- [x] Test progress bar display for various completion states
|
||||
- [x] Run existing test suite to ensure no regressions
|
||||
- [x] Verify TypeScript compilation with no errors
|
||||
|
||||
## Documentation
|
||||
- [x] Add command description in CLI help
|
||||
- [x] Create change proposal documentation
|
||||
- [x] Update README with view command example (if needed)
|
||||
- [x] Add view command to user documentation (if exists)
|
||||
|
||||
## Polish
|
||||
- [x] Ensure consistent formatting and alignment
|
||||
- [x] Add helpful footer text referencing list commands
|
||||
- [x] Optimize for terminal width considerations
|
||||
- [x] Review and refine color choices for accessibility
|
||||
@@ -0,0 +1,28 @@
|
||||
# Add AGENTS.md Standard Support To Init/Update
|
||||
|
||||
## Summary
|
||||
- Teach `openspec init` to manage a root-level `AGENTS.md` file using the same marker system as `CLAUDE.md`.
|
||||
- Allow `openspec update` to refresh or scaffold that root `AGENTS.md` so AGENTS-compatible tools always receive current instructions.
|
||||
- Keep the existing `openspec/AGENTS.md` template as the canonical source while ensuring assistants that read `AGENTS.md` opt-in instructions get the latest guidance automatically.
|
||||
|
||||
## Motivation
|
||||
The README now points teams to AGENTS.md-compatible assistants, but the CLI only manages `CLAUDE.md`. Projects must hand-roll a root `AGENTS.md` file to benefit from the standard, and updates will drift unless maintainers remember to copy content manually. Extending `init` and `update` closes that gap so OpenSpec actually delivers on the promise of first-class AGENTS support.
|
||||
|
||||
## Proposal
|
||||
1. Extend the `openspec init` selection flow with an "AGENTS.md standard" option that creates or refreshes a root `AGENTS.md` file wrapped in OpenSpec markers, mirroring the existing CLAUDE integration.
|
||||
2. When generating the file, pull the managed content from the same template used in `openspec/AGENTS.md`, ensuring both locations stay in sync.
|
||||
3. Update `openspec update` so it always refreshes the root `AGENTS.md` (creating it if missing) alongside `openspec/AGENTS.md` and any other configured assistants.
|
||||
4. Document the new behavior in CLI specs and verify marker handling (no duplicates, preserve user content outside the block) with tests for both commands.
|
||||
|
||||
## Out of Scope
|
||||
- Adding additional AGENTS-specific prompts or workflows beyond the shared instructions block.
|
||||
- Non-interactive flags or bulk configuration for multiple standards in one run.
|
||||
- Broader restructuring of how templates are stored or loaded.
|
||||
|
||||
## Risks & Mitigations
|
||||
- **Risk:** Accidentally overwriting user-edited content surrounding the managed block.
|
||||
- **Mitigation:** Reuse the existing marker-update helper shared with `CLAUDE.md`, and add tests that cover files containing custom text before and after the block.
|
||||
- **Risk:** Divergence between `openspec/AGENTS.md` and the root file.
|
||||
- **Mitigation:** Source the root file content from the canonical template rather than duplicating strings inline.
|
||||
- **Risk:** Confusion about when the file is created.
|
||||
- **Mitigation:** Log creation vs update, and ensure help text references the AGENTS option during `init`.
|
||||
@@ -0,0 +1,71 @@
|
||||
## MODIFIED Requirements
|
||||
### Requirement: AI Tool Configuration
|
||||
The command SHALL configure AI coding assistants with OpenSpec instructions based on user selection.
|
||||
|
||||
#### Scenario: Prompting for AI tool selection
|
||||
|
||||
- **WHEN** run
|
||||
- **THEN** prompt user to select AI tools to configure:
|
||||
- Claude Code (✅ OpenSpec custom slash commands available)
|
||||
- Cursor (✅ OpenSpec custom slash commands available)
|
||||
- AGENTS.md (works with Codex, Amp, Copilot, …)
|
||||
|
||||
### Requirement: AI Tool Configuration Details
|
||||
The command SHALL properly configure selected AI tools with OpenSpec-specific instructions using a marker system.
|
||||
|
||||
#### Scenario: Configuring Claude Code
|
||||
|
||||
- **WHEN** Claude Code is selected
|
||||
- **THEN** create or update `CLAUDE.md` in the project root directory (not inside openspec/)
|
||||
|
||||
#### Scenario: Configuring AGENTS standard
|
||||
|
||||
- **WHEN** the AGENTS.md standard is selected
|
||||
- **THEN** create or update `AGENTS.md` in the project root directory (not inside openspec/)
|
||||
|
||||
#### Scenario: Creating new CLAUDE.md
|
||||
|
||||
- **WHEN** CLAUDE.md does not exist
|
||||
- **THEN** create new file with OpenSpec content wrapped in markers:
|
||||
```markdown
|
||||
<!-- OPENSPEC:START -->
|
||||
# OpenSpec Project
|
||||
|
||||
This document provides instructions for AI coding assistants on how to use OpenSpec conventions for spec-driven development. Follow these rules precisely when working on OpenSpec-enabled projects.
|
||||
|
||||
This project uses OpenSpec for spec-driven development. Specifications are the source of truth.
|
||||
|
||||
See @openspec/AGENTS.md for detailed conventions and guidelines.
|
||||
<!-- OPENSPEC:END -->
|
||||
```
|
||||
|
||||
#### Scenario: Creating new AGENTS.md
|
||||
|
||||
- **WHEN** AGENTS.md does not exist in the project root
|
||||
- **THEN** create new file with OpenSpec content wrapped in markers using the same template as CLAUDE.md
|
||||
|
||||
#### Scenario: Updating existing CLAUDE.md
|
||||
|
||||
- **WHEN** CLAUDE.md already exists
|
||||
- **THEN** preserve all existing content
|
||||
- **AND** insert OpenSpec content at the beginning of the file using markers
|
||||
- **AND** ensure markers don't duplicate if they already exist
|
||||
|
||||
#### Scenario: Updating existing AGENTS.md
|
||||
|
||||
- **WHEN** AGENTS.md already exists in the project root
|
||||
- **THEN** preserve all existing content
|
||||
- **AND** ensure the OpenSpec-managed block at the beginning of the file is refreshed without duplicating markers
|
||||
|
||||
#### Scenario: Managing content with markers
|
||||
|
||||
- **WHEN** using the marker system
|
||||
- **THEN** use `<!-- OPENSPEC:START -->` to mark the beginning of managed content
|
||||
- **AND** use `<!-- OPENSPEC:END -->` to mark the end of managed content
|
||||
- **AND** allow OpenSpec to update its content without affecting user customizations
|
||||
- **AND** preserve all content outside the markers intact
|
||||
|
||||
WHY use markers:
|
||||
- Users may have existing CLAUDE.md or AGENTS.md instructions they want to keep
|
||||
- OpenSpec can update its instructions in future versions
|
||||
- Clear boundary between OpenSpec-managed and user-managed content
|
||||
@@ -0,0 +1,41 @@
|
||||
## MODIFIED Requirements
|
||||
### Requirement: Update Behavior
|
||||
The update command SHALL update OpenSpec instruction files to the latest templates in a team-friendly manner.
|
||||
|
||||
#### Scenario: Running update command
|
||||
|
||||
- **WHEN** a user runs `openspec update`
|
||||
- **THEN** the command SHALL:
|
||||
- Check if the `openspec` directory exists
|
||||
- Replace `openspec/AGENTS.md` with the latest template (complete replacement)
|
||||
- Create or refresh a root-level `AGENTS.md` file using the managed marker block (create if missing)
|
||||
- Update **only existing** AI tool configuration files (e.g., CLAUDE.md)
|
||||
- Check each registered AI tool configurator
|
||||
- For each configurator, check if its file exists
|
||||
- Update only files that already exist using their markers
|
||||
- Preserve user content outside markers
|
||||
- Display success message listing updated files
|
||||
|
||||
### Requirement: Tool-Agnostic Updates
|
||||
The update command SHALL handle file updates in a predictable and safe manner while respecting team tool choices.
|
||||
|
||||
#### Scenario: Updating files
|
||||
|
||||
- **WHEN** updating files
|
||||
- **THEN** completely replace `openspec/AGENTS.md` with the latest template
|
||||
- **AND** create or update the root-level `AGENTS.md` using the OpenSpec markers
|
||||
- **AND** update only the OpenSpec-managed blocks in **existing** AI tool files using markers
|
||||
- **AND** use the default directory name `openspec`
|
||||
- **AND** be idempotent (repeated runs have no additional effect)
|
||||
- **AND** respect team members' AI tool choices by not creating additional tool files beyond the root `AGENTS.md`
|
||||
|
||||
### Requirement: Core Files Always Updated
|
||||
The update command SHALL always update the core OpenSpec files and display an ASCII-safe success message.
|
||||
|
||||
#### Scenario: Successful update
|
||||
|
||||
- **WHEN** the update completes successfully
|
||||
- **THEN** replace `openspec/AGENTS.md` with the latest template
|
||||
- **AND** ensure the root-level `AGENTS.md` matches the latest template via the marker block
|
||||
- **AND** update existing AI tool configuration files within markers
|
||||
- **AND** display the message: "Updated OpenSpec instructions"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user