mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 00:21:21 +00:00
MAESTRO: feat(openspec): add GitHub refresh script and npm command
- Create scripts/refresh-openspec.mjs for build-time prompt updates - Add refresh-openspec npm script to package.json - Add extraResources for openspec prompts in all platform builds - Update bundled prompts with latest from OpenSpec repository
This commit is contained in:
15
package.json
15
package.json
@@ -45,7 +45,8 @@
|
||||
"test:integration": "vitest run --config vitest.integration.config.ts",
|
||||
"test:integration:watch": "vitest --config vitest.integration.config.ts",
|
||||
"test:performance": "vitest run --config vitest.performance.config.mts",
|
||||
"refresh-speckit": "node scripts/refresh-speckit.mjs"
|
||||
"refresh-speckit": "node scripts/refresh-speckit.mjs",
|
||||
"refresh-openspec": "node scripts/refresh-openspec.mjs"
|
||||
},
|
||||
"build": {
|
||||
"npmRebuild": false,
|
||||
@@ -99,6 +100,10 @@
|
||||
{
|
||||
"from": "src/prompts/speckit",
|
||||
"to": "prompts/speckit"
|
||||
},
|
||||
{
|
||||
"from": "src/prompts/openspec",
|
||||
"to": "prompts/openspec"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -127,6 +132,10 @@
|
||||
{
|
||||
"from": "src/prompts/speckit",
|
||||
"to": "prompts/speckit"
|
||||
},
|
||||
{
|
||||
"from": "src/prompts/openspec",
|
||||
"to": "prompts/openspec"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -164,6 +173,10 @@
|
||||
{
|
||||
"from": "src/prompts/speckit",
|
||||
"to": "prompts/speckit"
|
||||
},
|
||||
{
|
||||
"from": "src/prompts/openspec",
|
||||
"to": "prompts/openspec"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
216
scripts/refresh-openspec.mjs
Normal file
216
scripts/refresh-openspec.mjs
Normal file
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Refresh OpenSpec Prompts
|
||||
*
|
||||
* Fetches the latest OpenSpec prompts from GitHub by parsing AGENTS.md
|
||||
* and extracts the three workflow stages (proposal, apply, archive).
|
||||
*
|
||||
* Unlike spec-kit which uses ZIP releases, OpenSpec bundles all workflow
|
||||
* instructions in a single AGENTS.md file that we parse into sections.
|
||||
*
|
||||
* Usage: npm run refresh-openspec
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import https from 'https';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const OPENSPEC_DIR = path.join(__dirname, '..', 'src', 'prompts', 'openspec');
|
||||
const METADATA_PATH = path.join(OPENSPEC_DIR, 'metadata.json');
|
||||
|
||||
// GitHub OpenSpec repository info
|
||||
const GITHUB_API = 'https://api.github.com';
|
||||
const REPO_OWNER = 'Fission-AI';
|
||||
const REPO_NAME = 'OpenSpec';
|
||||
const AGENTS_MD_URL = `https://raw.githubusercontent.com/${REPO_OWNER}/${REPO_NAME}/main/openspec/AGENTS.md`;
|
||||
|
||||
// Commands to extract from AGENTS.md (we skip custom commands like 'help' and 'implement')
|
||||
const UPSTREAM_COMMANDS = ['proposal', 'apply', 'archive'];
|
||||
|
||||
// Section markers for parsing AGENTS.md
|
||||
// Stage headers are formatted as: ### Stage N: Title
|
||||
const SECTION_MARKERS = {
|
||||
proposal: {
|
||||
start: /^###\s*Stage\s*1[:\s]+Creating\s+Changes/i,
|
||||
end: /^###\s*Stage\s*2[:\s]+/i,
|
||||
},
|
||||
apply: {
|
||||
start: /^###\s*Stage\s*2[:\s]+Implementing\s+Changes/i,
|
||||
end: /^###\s*Stage\s*3[:\s]+/i,
|
||||
},
|
||||
archive: {
|
||||
start: /^###\s*Stage\s*3[:\s]+Archiving\s+Changes/i,
|
||||
end: /^##[^#]/, // End at next level-2 heading or end of file
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Make an HTTPS GET request
|
||||
*/
|
||||
function httpsGet(url, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const headers = {
|
||||
'User-Agent': 'Maestro-OpenSpec-Refresher',
|
||||
...options.headers,
|
||||
};
|
||||
|
||||
https.get(url, { headers }, (res) => {
|
||||
// Handle redirects
|
||||
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||
return resolve(httpsGet(res.headers.location, options));
|
||||
}
|
||||
|
||||
if (res.statusCode !== 200) {
|
||||
reject(new Error(`HTTP ${res.statusCode}: ${url}`));
|
||||
return;
|
||||
}
|
||||
|
||||
let data = '';
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => resolve({ data, headers: res.headers }));
|
||||
res.on('error', reject);
|
||||
}).on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse AGENTS.md and extract workflow sections as prompts
|
||||
*/
|
||||
function parseAgentsMd(content) {
|
||||
const result = {};
|
||||
const lines = content.split('\n');
|
||||
|
||||
for (const [sectionId, markers] of Object.entries(SECTION_MARKERS)) {
|
||||
let inSection = false;
|
||||
let sectionLines = [];
|
||||
|
||||
for (const line of lines) {
|
||||
if (!inSection && markers.start.test(line)) {
|
||||
inSection = true;
|
||||
sectionLines.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inSection) {
|
||||
// Check if we've hit the end marker (next stage or next major section)
|
||||
if (markers.end.test(line) && line.trim() !== '') {
|
||||
// Don't include the end marker line, it belongs to the next section
|
||||
break;
|
||||
}
|
||||
sectionLines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (sectionLines.length > 0) {
|
||||
// Clean up trailing empty lines
|
||||
while (sectionLines.length > 0 && sectionLines[sectionLines.length - 1].trim() === '') {
|
||||
sectionLines.pop();
|
||||
}
|
||||
result[sectionId] = sectionLines.join('\n').trim();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest commit SHA from the main branch
|
||||
*/
|
||||
async function getLatestCommitSha() {
|
||||
try {
|
||||
const url = `${GITHUB_API}/repos/${REPO_OWNER}/${REPO_NAME}/commits/main`;
|
||||
const { data } = await httpsGet(url);
|
||||
const commit = JSON.parse(data);
|
||||
return commit.sha.substring(0, 7);
|
||||
} catch (error) {
|
||||
console.warn(' Warning: Could not fetch commit SHA, using "main"');
|
||||
return 'main';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main refresh function
|
||||
*/
|
||||
async function refreshOpenSpec() {
|
||||
console.log('🔄 Refreshing OpenSpec prompts from GitHub...\n');
|
||||
|
||||
// Ensure openspec directory exists
|
||||
if (!fs.existsSync(OPENSPEC_DIR)) {
|
||||
console.error('❌ OpenSpec directory not found:', OPENSPEC_DIR);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
// Fetch AGENTS.md
|
||||
console.log('📡 Fetching AGENTS.md from OpenSpec repository...');
|
||||
const { data: agentsMdContent } = await httpsGet(AGENTS_MD_URL);
|
||||
console.log(` Downloaded AGENTS.md (${agentsMdContent.length} bytes)`);
|
||||
|
||||
// Parse sections
|
||||
console.log('\n📦 Parsing workflow sections...');
|
||||
const extractedPrompts = parseAgentsMd(agentsMdContent);
|
||||
const extractedCount = Object.keys(extractedPrompts).length;
|
||||
console.log(` Extracted ${extractedCount} sections from AGENTS.md`);
|
||||
|
||||
if (extractedCount === 0) {
|
||||
console.error('❌ Failed to extract any sections from AGENTS.md');
|
||||
console.error(' Check that the section markers match the current format');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Get commit SHA for version tracking
|
||||
console.log('\n📋 Getting version info...');
|
||||
const commitSha = await getLatestCommitSha();
|
||||
console.log(` Commit: ${commitSha}`);
|
||||
|
||||
// Update prompt files
|
||||
console.log('\n✏️ Updating prompt files...');
|
||||
let updatedCount = 0;
|
||||
for (const commandName of UPSTREAM_COMMANDS) {
|
||||
const content = extractedPrompts[commandName];
|
||||
if (!content) {
|
||||
console.log(` ⚠ Missing: openspec.${commandName}.md (section not found)`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const promptFile = path.join(OPENSPEC_DIR, `openspec.${commandName}.md`);
|
||||
const existingContent = fs.existsSync(promptFile)
|
||||
? fs.readFileSync(promptFile, 'utf8')
|
||||
: '';
|
||||
|
||||
if (content !== existingContent) {
|
||||
fs.writeFileSync(promptFile, content);
|
||||
console.log(` ✓ Updated: openspec.${commandName}.md`);
|
||||
updatedCount++;
|
||||
} else {
|
||||
console.log(` - Unchanged: openspec.${commandName}.md`);
|
||||
}
|
||||
}
|
||||
|
||||
// Update metadata
|
||||
const metadata = {
|
||||
lastRefreshed: new Date().toISOString(),
|
||||
commitSha,
|
||||
sourceVersion: '0.1.0',
|
||||
sourceUrl: `https://github.com/${REPO_OWNER}/${REPO_NAME}`,
|
||||
};
|
||||
|
||||
fs.writeFileSync(METADATA_PATH, JSON.stringify(metadata, null, 2));
|
||||
console.log('\n📄 Updated metadata.json');
|
||||
|
||||
// Summary
|
||||
console.log('\n✅ Refresh complete!');
|
||||
console.log(` Commit: ${commitSha}`);
|
||||
console.log(` Updated: ${updatedCount} files`);
|
||||
console.log(` Skipped: help, implement (custom Maestro prompts)`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('\n❌ Refresh failed:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Run
|
||||
refreshOpenSpec();
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"lastRefreshed": "2025-01-01T00:00:00Z",
|
||||
"commitSha": "main",
|
||||
"lastRefreshed": "2025-12-27T17:46:57.133Z",
|
||||
"commitSha": "8dcd170",
|
||||
"sourceVersion": "0.1.0",
|
||||
"sourceUrl": "https://github.com/Fission-AI/OpenSpec"
|
||||
}
|
||||
}
|
||||
@@ -1,136 +1,9 @@
|
||||
# OpenSpec Apply - Stage 2: Implementing Changes
|
||||
|
||||
You are helping the user implement an approved OpenSpec change proposal. This is Stage 2 of the OpenSpec workflow.
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
**IMPORTANT: Do not start implementation until the proposal is reviewed and approved.**
|
||||
|
||||
The approval gate ensures alignment between stakeholders before coding begins. If the proposal hasn't been approved yet, remind the user to get approval first.
|
||||
|
||||
## Implementation Workflow
|
||||
|
||||
### Step 1: Review the Proposal
|
||||
|
||||
Read `proposal.md` to understand:
|
||||
- **Why** - The problem or opportunity being addressed
|
||||
- **What** - The specific changes being made
|
||||
- **Impact** - Which specs, code, and systems are affected
|
||||
|
||||
```bash
|
||||
openspec show <change-id>
|
||||
```
|
||||
|
||||
### Step 2: Review Technical Decisions
|
||||
|
||||
If `design.md` exists, review it for:
|
||||
- Key architectural decisions
|
||||
- Chosen approaches and trade-offs
|
||||
- Migration plan (if applicable)
|
||||
- Known risks to watch for
|
||||
|
||||
### Step 3: Study the Tasks
|
||||
|
||||
Read `tasks.md` for the implementation checklist:
|
||||
- Tasks are numbered and ordered by dependency
|
||||
- Each phase should be completed before moving to the next
|
||||
- Tasks with `[P]` marker can run in parallel
|
||||
|
||||
### Step 4: Execute Tasks Sequentially
|
||||
|
||||
For each task in `tasks.md`:
|
||||
|
||||
1. **Read the task description** carefully
|
||||
2. **Implement the required changes**
|
||||
3. **Verify the implementation** works as expected
|
||||
4. **Test related functionality** to catch regressions
|
||||
5. **Mark the task complete** by changing `- [ ]` to `- [x]`
|
||||
|
||||
```markdown
|
||||
# Before
|
||||
- [ ] T001 Implement user authentication endpoint
|
||||
|
||||
# After
|
||||
- [x] T001 Implement user authentication endpoint
|
||||
```
|
||||
|
||||
### Step 5: Confirm Completion
|
||||
|
||||
Before marking the change as complete:
|
||||
|
||||
1. **Verify every task** is checked (`- [x]`)
|
||||
2. **Run validation** to ensure specs are consistent:
|
||||
```bash
|
||||
openspec validate <change-id> --strict
|
||||
```
|
||||
3. **Run project tests** to verify no regressions
|
||||
4. **Review the spec deltas** match what was implemented
|
||||
|
||||
## Implementation Guidelines
|
||||
|
||||
### Following Task Order
|
||||
|
||||
Tasks are dependency-ordered. Complete them in sequence unless marked with `[P]`:
|
||||
|
||||
```markdown
|
||||
- [x] T001 Setup database migration # Do first
|
||||
- [x] T002 Create User model # Do second
|
||||
- [x] T003 [P] Add unit tests # Can run parallel with T004
|
||||
- [x] T004 [P] Add integration tests # Can run parallel with T003
|
||||
- [x] T005 Update API documentation # Do after T003 & T004
|
||||
```
|
||||
|
||||
### Handling Blockers
|
||||
|
||||
If you encounter a blocker:
|
||||
|
||||
1. **Document the issue** in the task notes
|
||||
2. **Ask clarifying questions** if requirements are unclear
|
||||
3. **Update the proposal** if scope needs adjustment (requires re-approval)
|
||||
4. **Don't skip tasks** - blockers should be resolved, not bypassed
|
||||
|
||||
### Quality Checks
|
||||
|
||||
For each task:
|
||||
|
||||
- **Code quality** - Follow project conventions from `openspec/project.md`
|
||||
- **Test coverage** - Add tests for new functionality
|
||||
- **Documentation** - Update docs if behavior changes
|
||||
- **Type safety** - Ensure type definitions are complete
|
||||
|
||||
## Helpful Commands
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `openspec show <change-id>` | Display full change details |
|
||||
| `openspec validate <change-id> --strict` | Validate change consistency |
|
||||
| `openspec list` | View all active changes |
|
||||
| `openspec diff <change-id>` | Show spec differences |
|
||||
|
||||
## When Implementation is Complete
|
||||
|
||||
Once all tasks are marked `[x]` and validation passes:
|
||||
|
||||
1. **Commit your changes** with a descriptive message referencing the change-id
|
||||
2. **Create a pull request** for review
|
||||
3. **Wait for deployment** before proceeding to Stage 3 (Archive)
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: implement <change-id> - <brief description>"
|
||||
```
|
||||
|
||||
## Key Principles
|
||||
|
||||
- **Complete tasks in order** - Dependencies exist for a reason
|
||||
- **Verify before marking done** - Each `[x]` represents tested, working code
|
||||
- **Don't shortcut** - If something is unclear, ask rather than assume
|
||||
- **Keep specs in sync** - Implemented behavior should match spec deltas
|
||||
### 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
|
||||
@@ -1,162 +1,6 @@
|
||||
# OpenSpec Archive - Stage 3: Archiving Changes
|
||||
|
||||
You are helping the user archive a completed OpenSpec change. This is Stage 3 of the OpenSpec workflow.
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
**IMPORTANT: Archive only after deployment.**
|
||||
|
||||
Stage 3 should be run after:
|
||||
1. All tasks in `tasks.md` are marked complete (`- [x]`)
|
||||
2. The code has been reviewed and merged
|
||||
3. The changes have been deployed to production (or the target environment)
|
||||
|
||||
## Archive Workflow
|
||||
|
||||
### Step 1: Verify Completion
|
||||
|
||||
Before archiving, confirm:
|
||||
|
||||
```bash
|
||||
# Check all tasks are complete
|
||||
openspec show <change-id>
|
||||
|
||||
# Validate the change passes all checks
|
||||
openspec validate <change-id> --strict
|
||||
```
|
||||
|
||||
### Step 2: Archive the Change
|
||||
|
||||
Move the change directory to archive with a date prefix:
|
||||
|
||||
```bash
|
||||
openspec archive <change-id> --yes
|
||||
```
|
||||
|
||||
This command:
|
||||
1. **Moves** `openspec/changes/<change-id>/` to `openspec/changes/archive/YYYY-MM-DD-<change-id>/`
|
||||
2. **Updates** `openspec/specs/` with any capability changes
|
||||
3. **Validates** the archived change passes all checks
|
||||
|
||||
### Step 3: Verify Archive Success
|
||||
|
||||
After archiving:
|
||||
|
||||
```bash
|
||||
# Confirm change is no longer in active list
|
||||
openspec list
|
||||
|
||||
# Verify specs were updated correctly
|
||||
openspec validate --strict
|
||||
```
|
||||
|
||||
## Manual Archive Process
|
||||
|
||||
If you need to archive manually (without the CLI):
|
||||
|
||||
### 1. Create Archive Directory
|
||||
|
||||
```bash
|
||||
mkdir -p openspec/changes/archive/$(date +%Y-%m-%d)-<change-id>
|
||||
mv openspec/changes/<change-id>/* openspec/changes/archive/$(date +%Y-%m-%d)-<change-id>/
|
||||
rmdir openspec/changes/<change-id>
|
||||
```
|
||||
|
||||
### 2. Update Main Specs
|
||||
|
||||
If the change modified existing specs, merge the deltas:
|
||||
|
||||
1. **For ADDED requirements** - Copy to `openspec/specs/<capability>/spec.md`
|
||||
2. **For MODIFIED requirements** - Replace the original requirement with the modified version
|
||||
3. **For REMOVED requirements** - Delete from `openspec/specs/<capability>/spec.md`
|
||||
4. **For RENAMED requirements** - Update the name in place
|
||||
|
||||
### 3. Clean Up Spec Deltas
|
||||
|
||||
The archived change should retain its spec deltas for historical reference, but the main `specs/` directory should now reflect the deployed state.
|
||||
|
||||
## Archive Options
|
||||
|
||||
```bash
|
||||
# Standard archive (prompts for confirmation)
|
||||
openspec archive <change-id>
|
||||
|
||||
# Skip confirmation prompt
|
||||
openspec archive <change-id> --yes
|
||||
openspec archive <change-id> -y
|
||||
|
||||
# Skip spec updates (for tooling-only changes)
|
||||
openspec archive <change-id> --skip-specs
|
||||
```
|
||||
|
||||
**Note:** Always pass the change-id explicitly. Don't rely on positional inference.
|
||||
|
||||
## Validation After Archive
|
||||
|
||||
Run comprehensive validation to confirm:
|
||||
|
||||
```bash
|
||||
openspec validate --strict
|
||||
```
|
||||
|
||||
This validates:
|
||||
- All archived changes pass validation
|
||||
- Main specs are internally consistent
|
||||
- No orphaned references exist
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Spec Conflicts
|
||||
|
||||
If archiving fails due to spec conflicts:
|
||||
|
||||
1. **Review the conflict** - Check which requirements clash
|
||||
2. **Resolve manually** - Edit `specs/<capability>/spec.md` to resolve
|
||||
3. **Re-run validation** - Ensure consistency after manual fixes
|
||||
4. **Document resolution** - Note any manual interventions
|
||||
|
||||
### Missing Archive Directory
|
||||
|
||||
If the archive directory doesn't exist:
|
||||
|
||||
```bash
|
||||
mkdir -p openspec/changes/archive
|
||||
```
|
||||
|
||||
### Partial Archive
|
||||
|
||||
If archive was interrupted:
|
||||
|
||||
1. **Check for duplicate files** in both `changes/` and `changes/archive/`
|
||||
2. **Complete the move** manually if needed
|
||||
3. **Run validation** to confirm state is correct
|
||||
|
||||
## Post-Archive Checklist
|
||||
|
||||
After successfully archiving:
|
||||
|
||||
- [ ] Change is in `openspec/changes/archive/YYYY-MM-DD-<change-id>/`
|
||||
- [ ] Active change list (`openspec list`) no longer shows it
|
||||
- [ ] Main specs reflect deployed state
|
||||
- [ ] Validation passes (`openspec validate --strict`)
|
||||
- [ ] Git commit includes the archive change
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "chore: archive <change-id> after deployment"
|
||||
```
|
||||
|
||||
## Key Principles
|
||||
|
||||
- **Archive promptly** - Don't let changes linger after deployment
|
||||
- **Keep history** - Archived changes serve as documentation
|
||||
- **Specs are truth** - After archiving, `specs/` represents deployed reality
|
||||
- **Validate always** - Run validation before and after archiving
|
||||
### 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
|
||||
@@ -1,203 +1,31 @@
|
||||
# OpenSpec Proposal - Stage 1: Creating Changes
|
||||
|
||||
You are helping the user create an OpenSpec change proposal. This is Stage 1 of the OpenSpec workflow.
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## When to Create a Proposal
|
||||
|
||||
Create a proposal when making substantial modifications:
|
||||
|
||||
- Adding new features or functionality
|
||||
- Implementing breaking changes (APIs, schemas)
|
||||
- Changing architectural patterns
|
||||
- Optimizing performance that affects behavior
|
||||
- Updating security patterns
|
||||
|
||||
**Skip proposal for:** bug fixes, typos, comments, non-breaking dependency updates, and configuration-only changes.
|
||||
|
||||
## Stage 1 Workflow
|
||||
|
||||
Follow these steps to create a complete change proposal:
|
||||
|
||||
### Step 1: Review Existing Context
|
||||
|
||||
Before creating a proposal:
|
||||
|
||||
1. **Check `openspec/project.md`** for project conventions and context
|
||||
2. **Run `openspec list`** to see active changes (avoid conflicts)
|
||||
3. **Run `openspec list --specs`** to view existing capabilities
|
||||
4. **Use `openspec show [spec]`** to review current specification state
|
||||
|
||||
### Step 2: Choose a Unique Change-ID
|
||||
|
||||
- Use **kebab-case** naming
|
||||
- Use **verb-led** format:
|
||||
- `add-` for new features
|
||||
- `update-` for modifications
|
||||
- `remove-` for deprecations
|
||||
- `refactor-` for structural changes
|
||||
- Ensure uniqueness (append `-2` or `-3` if needed)
|
||||
|
||||
**Examples:** `add-user-authentication`, `update-api-v2-endpoints`, `remove-legacy-cache`
|
||||
|
||||
### Step 3: Scaffold Directory Structure
|
||||
|
||||
Create the following structure:
|
||||
|
||||
```
|
||||
openspec/changes/[change-id]/
|
||||
├── proposal.md # What and why
|
||||
├── tasks.md # Implementation checklist
|
||||
├── design.md # Optional: technical decisions
|
||||
└── specs/ # Spec deltas
|
||||
└── [capability]/
|
||||
└── spec.md
|
||||
```
|
||||
|
||||
### Step 4: Write proposal.md
|
||||
|
||||
Create `proposal.md` with these sections:
|
||||
|
||||
```markdown
|
||||
# [Change Title]
|
||||
|
||||
## Why
|
||||
|
||||
1–2 sentences explaining the problem or opportunity this addresses.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Bulleted list of modifications
|
||||
- Mark breaking changes as **BREAKING**
|
||||
- Be specific about affected components
|
||||
|
||||
## Impact
|
||||
|
||||
- List affected specs
|
||||
- List affected code modules
|
||||
- List affected external systems
|
||||
```
|
||||
|
||||
### Step 5: Create Spec Deltas
|
||||
|
||||
In `specs/[capability]/spec.md`, use operation headers:
|
||||
|
||||
```markdown
|
||||
## ADDED Requirements
|
||||
|
||||
New, standalone capabilities that don't exist yet.
|
||||
|
||||
### REQ-001: Requirement Title
|
||||
|
||||
Description of the new requirement.
|
||||
|
||||
#### Scenario: Success case
|
||||
- **WHEN** specific conditions are met
|
||||
- **THEN** expected outcome occurs
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
Changed behavior or scope of existing requirements.
|
||||
|
||||
### REQ-002: Existing Requirement (Modified)
|
||||
|
||||
Updated description reflecting new behavior.
|
||||
|
||||
#### Scenario: Updated behavior
|
||||
- **WHEN** new conditions apply
|
||||
- **THEN** new outcome expected
|
||||
|
||||
## REMOVED Requirements
|
||||
|
||||
Deprecated features being removed.
|
||||
|
||||
### REQ-003: Deprecated Feature
|
||||
|
||||
**Reason:** Explain why this is being removed
|
||||
**Migration:** Describe how users should migrate
|
||||
|
||||
## RENAMED Requirements
|
||||
|
||||
Name-only changes (no behavior change).
|
||||
|
||||
### REQ-004: Old Name → New Name
|
||||
```
|
||||
|
||||
**Critical Rules:**
|
||||
- Include at least one `#### Scenario:` per requirement (use 4 hashtags)
|
||||
- Use `**WHEN**` and `**THEN**` bullets within scenarios
|
||||
- For MODIFIED requirements, copy the entire existing requirement block and edit it
|
||||
- Header text must match exactly (whitespace-insensitive) when modifying
|
||||
|
||||
### Step 6: Create tasks.md
|
||||
|
||||
Create a structured implementation checklist:
|
||||
|
||||
```markdown
|
||||
# Implementation Tasks
|
||||
|
||||
## Phase 1: Setup
|
||||
|
||||
- [ ] T001 Initial setup task
|
||||
- [ ] T002 Configuration task
|
||||
|
||||
## Phase 2: Core Implementation
|
||||
|
||||
- [ ] T003 Main feature implementation
|
||||
- [ ] T004 Supporting functionality
|
||||
- [ ] T005 Integration work
|
||||
|
||||
## Phase 3: Testing & Documentation
|
||||
|
||||
- [ ] T006 Add unit tests
|
||||
- [ ] T007 Add integration tests
|
||||
- [ ] T008 Update documentation
|
||||
```
|
||||
|
||||
### Step 7: Optional - Create design.md
|
||||
|
||||
Create `design.md` only when needed for:
|
||||
- Cross-cutting changes affecting multiple systems
|
||||
- New dependencies or external integrations
|
||||
- Significant data model changes
|
||||
- Security or performance complexity
|
||||
|
||||
**design.md sections:**
|
||||
- Context
|
||||
- Goals / Non-Goals
|
||||
- Key Decisions
|
||||
- Risks & Trade-offs
|
||||
- Migration Plan (if applicable)
|
||||
- Open Questions
|
||||
|
||||
### Step 8: Validate Before Sharing
|
||||
|
||||
Always validate your proposal:
|
||||
|
||||
```bash
|
||||
openspec validate <change-id> --strict
|
||||
```
|
||||
|
||||
Fix all issues identified by validation. Use `openspec show <change-id> --json --deltas-only` for debugging.
|
||||
|
||||
## Key Principles
|
||||
|
||||
- **Specs are truth** - The `specs/` directory reflects what is built
|
||||
- **Changes are proposals** - The `changes/` directory contains planned modifications
|
||||
- **Ask before ambiguity** - If the request is unclear, ask 1–2 clarifying questions before scaffolding
|
||||
|
||||
## Helpful Commands
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `openspec list` | View active changes |
|
||||
| `openspec list --specs` | List existing capabilities |
|
||||
| `openspec show [item]` | Display change or spec details |
|
||||
| `openspec validate [item] --strict` | Comprehensive validation |
|
||||
### 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.
|
||||
Reference in New Issue
Block a user