@fission-ai/openspec 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -140,6 +140,8 @@ These tools automatically read workflow instructions from `openspec/AGENTS.md`.
140
140
 
141
141
  #### Step 1: Install the CLI globally
142
142
 
143
+ **Option A: Using npm**
144
+
143
145
  ```bash
144
146
  npm install -g @fission-ai/openspec@latest
145
147
  ```
@@ -149,6 +151,39 @@ Verify installation:
149
151
  openspec --version
150
152
  ```
151
153
 
154
+ **Option B: Using Nix (NixOS and Nix package manager)**
155
+
156
+ Run OpenSpec directly without installation:
157
+ ```bash
158
+ nix run github:Fission-AI/OpenSpec -- init
159
+ ```
160
+
161
+ Or install to your profile:
162
+ ```bash
163
+ nix profile install github:Fission-AI/OpenSpec
164
+ ```
165
+
166
+ Or add to your development environment in `flake.nix`:
167
+ ```nix
168
+ {
169
+ inputs = {
170
+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
171
+ openspec.url = "github:Fission-AI/OpenSpec";
172
+ };
173
+
174
+ outputs = { nixpkgs, openspec, ... }: {
175
+ devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {
176
+ buildInputs = [ openspec.packages.x86_64-linux.default ];
177
+ };
178
+ };
179
+ }
180
+ ```
181
+
182
+ Verify installation:
183
+ ```bash
184
+ openspec --version
185
+ ```
186
+
152
187
  #### Step 2: Initialize OpenSpec in your project
153
188
 
154
189
  Navigate to your project directory:
package/dist/cli/index.js CHANGED
@@ -13,6 +13,7 @@ import { ChangeCommand } from '../commands/change.js';
13
13
  import { ValidateCommand } from '../commands/validate.js';
14
14
  import { ShowCommand } from '../commands/show.js';
15
15
  import { CompletionCommand } from '../commands/completion.js';
16
+ import { FeedbackCommand } from '../commands/feedback.js';
16
17
  import { registerConfigCommand } from '../commands/config.js';
17
18
  import { registerArtifactWorkflowCommands } from '../commands/artifact-workflow.js';
18
19
  import { maybeShowTelemetryNotice, trackCommand, shutdown } from '../telemetry/index.js';
@@ -279,6 +280,22 @@ program
279
280
  process.exit(1);
280
281
  }
281
282
  });
283
+ // Feedback command
284
+ program
285
+ .command('feedback <message>')
286
+ .description('Submit feedback about OpenSpec')
287
+ .option('--body <text>', 'Detailed description for the feedback')
288
+ .action(async (message, options) => {
289
+ try {
290
+ const feedbackCommand = new FeedbackCommand();
291
+ await feedbackCommand.execute(message, options);
292
+ }
293
+ catch (error) {
294
+ console.log();
295
+ ora().fail(`Error: ${error.message}`);
296
+ process.exit(1);
297
+ }
298
+ });
282
299
  // Completion command with subcommands
283
300
  const completionCmd = program
284
301
  .command('completion')
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Feedback command implementation
3
+ */
4
+ export declare class FeedbackCommand {
5
+ execute(message: string, options?: {
6
+ body?: string;
7
+ }): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=feedback.d.ts.map
@@ -0,0 +1,183 @@
1
+ import { execSync, execFileSync } from 'child_process';
2
+ import { createRequire } from 'module';
3
+ import os from 'os';
4
+ const require = createRequire(import.meta.url);
5
+ /**
6
+ * Check if gh CLI is installed and available in PATH
7
+ * Uses platform-appropriate command: 'where' on Windows, 'which' on Unix/macOS
8
+ */
9
+ function isGhInstalled() {
10
+ try {
11
+ const command = process.platform === 'win32' ? 'where gh' : 'which gh';
12
+ execSync(command, { stdio: 'pipe' });
13
+ return true;
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ /**
20
+ * Check if gh CLI is authenticated
21
+ */
22
+ function isGhAuthenticated() {
23
+ try {
24
+ execSync('gh auth status', { stdio: 'pipe' });
25
+ return true;
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ }
31
+ /**
32
+ * Get OpenSpec version from package.json
33
+ */
34
+ function getVersion() {
35
+ try {
36
+ const { version } = require('../../package.json');
37
+ return version;
38
+ }
39
+ catch {
40
+ return 'unknown';
41
+ }
42
+ }
43
+ /**
44
+ * Get platform name
45
+ */
46
+ function getPlatform() {
47
+ return os.platform();
48
+ }
49
+ /**
50
+ * Get current timestamp in ISO format
51
+ */
52
+ function getTimestamp() {
53
+ return new Date().toISOString();
54
+ }
55
+ /**
56
+ * Generate metadata footer for feedback
57
+ */
58
+ function generateMetadata() {
59
+ const version = getVersion();
60
+ const platform = getPlatform();
61
+ const timestamp = getTimestamp();
62
+ return `---
63
+ Submitted via OpenSpec CLI
64
+ - Version: ${version}
65
+ - Platform: ${platform}
66
+ - Timestamp: ${timestamp}`;
67
+ }
68
+ /**
69
+ * Format the feedback title
70
+ */
71
+ function formatTitle(message) {
72
+ return `Feedback: ${message}`;
73
+ }
74
+ /**
75
+ * Format the full feedback body
76
+ */
77
+ function formatBody(bodyText) {
78
+ const parts = [];
79
+ if (bodyText) {
80
+ parts.push(bodyText);
81
+ parts.push(''); // Empty line before metadata
82
+ }
83
+ parts.push(generateMetadata());
84
+ return parts.join('\n');
85
+ }
86
+ /**
87
+ * Generate a pre-filled GitHub issue URL for manual submission
88
+ */
89
+ function generateManualSubmissionUrl(title, body) {
90
+ const repo = 'Fission-AI/OpenSpec';
91
+ const encodedTitle = encodeURIComponent(title);
92
+ const encodedBody = encodeURIComponent(body);
93
+ const encodedLabels = encodeURIComponent('feedback');
94
+ return `https://github.com/${repo}/issues/new?title=${encodedTitle}&body=${encodedBody}&labels=${encodedLabels}`;
95
+ }
96
+ /**
97
+ * Display formatted feedback content for manual submission
98
+ */
99
+ function displayFormattedFeedback(title, body) {
100
+ console.log('\n--- FORMATTED FEEDBACK ---');
101
+ console.log(`Title: ${title}`);
102
+ console.log(`Labels: feedback`);
103
+ console.log('\nBody:');
104
+ console.log(body);
105
+ console.log('--- END FEEDBACK ---\n');
106
+ }
107
+ /**
108
+ * Submit feedback via gh CLI
109
+ * Uses execFileSync to prevent shell injection vulnerabilities
110
+ */
111
+ function submitViaGhCli(title, body) {
112
+ try {
113
+ const result = execFileSync('gh', [
114
+ 'issue',
115
+ 'create',
116
+ '--repo',
117
+ 'Fission-AI/OpenSpec',
118
+ '--title',
119
+ title,
120
+ '--body',
121
+ body,
122
+ '--label',
123
+ 'feedback',
124
+ ], { encoding: 'utf-8', stdio: 'pipe' });
125
+ const issueUrl = result.trim();
126
+ console.log(`\n✓ Feedback submitted successfully!`);
127
+ console.log(`Issue URL: ${issueUrl}\n`);
128
+ }
129
+ catch (error) {
130
+ // Display the error output from gh CLI
131
+ if (error.stderr) {
132
+ console.error(error.stderr.toString());
133
+ }
134
+ else if (error.message) {
135
+ console.error(error.message);
136
+ }
137
+ // Exit with the same code as gh CLI
138
+ process.exit(error.status ?? 1);
139
+ }
140
+ }
141
+ /**
142
+ * Handle fallback when gh CLI is not available or not authenticated
143
+ */
144
+ function handleFallback(title, body, reason) {
145
+ if (reason === 'missing') {
146
+ console.log('⚠️ GitHub CLI not found. Manual submission required.');
147
+ }
148
+ else {
149
+ console.log('⚠️ GitHub authentication required. Manual submission required.');
150
+ }
151
+ displayFormattedFeedback(title, body);
152
+ const manualUrl = generateManualSubmissionUrl(title, body);
153
+ console.log('Please submit your feedback manually:');
154
+ console.log(manualUrl);
155
+ if (reason === 'unauthenticated') {
156
+ console.log('\nTo auto-submit in the future: gh auth login');
157
+ }
158
+ // Exit with success code (fallback is successful)
159
+ process.exit(0);
160
+ }
161
+ /**
162
+ * Feedback command implementation
163
+ */
164
+ export class FeedbackCommand {
165
+ async execute(message, options) {
166
+ // Format title and body once for all code paths
167
+ const title = formatTitle(message);
168
+ const body = formatBody(options?.body);
169
+ // Check if gh CLI is installed
170
+ if (!isGhInstalled()) {
171
+ handleFallback(title, body, 'missing');
172
+ return;
173
+ }
174
+ // Check if gh CLI is authenticated
175
+ if (!isGhAuthenticated()) {
176
+ handleFallback(title, body, 'unauthenticated');
177
+ return;
178
+ }
179
+ // Submit via gh CLI
180
+ submitViaGhCli(title, body);
181
+ }
182
+ }
183
+ //# sourceMappingURL=feedback.js.map
@@ -152,6 +152,18 @@ export const COMMAND_REGISTRY = [
152
152
  },
153
153
  ],
154
154
  },
155
+ {
156
+ name: 'feedback',
157
+ description: 'Submit feedback about OpenSpec',
158
+ acceptsPositional: true,
159
+ flags: [
160
+ {
161
+ name: 'body',
162
+ description: 'Detailed description for the feedback',
163
+ takesValue: true,
164
+ },
165
+ ],
166
+ },
155
167
  {
156
168
  name: 'change',
157
169
  description: 'Manage OpenSpec change proposals (deprecated)',
@@ -92,4 +92,9 @@ export declare function getOpsxArchiveCommandTemplate(): CommandTemplate;
92
92
  * Template for /opsx:verify slash command
93
93
  */
94
94
  export declare function getOpsxVerifyCommandTemplate(): CommandTemplate;
95
+ /**
96
+ * Template for feedback skill
97
+ * For collecting and submitting user feedback with context enrichment
98
+ */
99
+ export declare function getFeedbackSkillTemplate(): SkillTemplate;
95
100
  //# sourceMappingURL=skill-templates.d.ts.map
@@ -17,6 +17,8 @@ export function getExploreSkillTemplate() {
17
17
  description: 'Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.',
18
18
  instructions: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes.
19
19
 
20
+ **IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first (e.g., start a change with \`/opsx:new\` or \`/opsx:ff\`). You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing.
21
+
20
22
  **This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore.
21
23
 
22
24
  ---
@@ -24,6 +26,7 @@ export function getExploreSkillTemplate() {
24
26
  ## The Stance
25
27
 
26
28
  - **Curious, not prescriptive** - Ask questions that emerge naturally, don't follow a script
29
+ - **Open threads, not interrogations** - Surface multiple interesting directions and let the user follow what resonates. Don't funnel them through a single path of questions.
27
30
  - **Visual** - Use ASCII diagrams liberally when they'd help clarify thinking
28
31
  - **Adaptive** - Follow interesting threads, pivot when new information emerges
29
32
  - **Patient** - Don't rush to conclusions, let the shape of the problem emerge
@@ -283,6 +286,7 @@ But this summary is optional. Sometimes the thinking IS the value.
283
286
 
284
287
  ## Guardrails
285
288
 
289
+ - **Don't implement** - Never write code or implement features. Creating OpenSpec artifacts is fine, writing application code is not.
286
290
  - **Don't fake understanding** - If something is unclear, dig deeper
287
291
  - **Don't rush** - Discovery is thinking time, not task time
288
292
  - **Don't force structure** - Let patterns emerge naturally
@@ -376,7 +380,7 @@ export function getContinueChangeSkillTemplate() {
376
380
  description: 'Continue working on an OpenSpec change by creating the next artifact. Use when the user wants to progress their change, create the next artifact, or continue their workflow.',
377
381
  instructions: `Continue working on a change by creating the next artifact.
378
382
 
379
- **Input**: Optionally specify a change name. If omitted, MUST prompt for available changes.
383
+ **Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
380
384
 
381
385
  **Steps**
382
386
 
@@ -489,19 +493,18 @@ export function getApplyChangeSkillTemplate() {
489
493
  description: 'Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.',
490
494
  instructions: `Implement tasks from an OpenSpec change.
491
495
 
492
- **Input**: Optionally specify a change name. If omitted, MUST prompt for available changes.
496
+ **Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
493
497
 
494
498
  **Steps**
495
499
 
496
- 1. **If no change name provided, prompt for selection**
500
+ 1. **Select the change**
497
501
 
498
- Run \`openspec list --json\` to get available changes. Use the **AskUserQuestion tool** to let the user select.
502
+ If a name is provided, use it. Otherwise:
503
+ - Infer from conversation context if the user mentioned a change
504
+ - Auto-select if only one active change exists
505
+ - If ambiguous, run \`openspec list --json\` to get available changes and use the **AskUserQuestion tool** to let the user select
499
506
 
500
- Show changes that are implementation-ready (have tasks artifact).
501
- Include the schema used for each change if available.
502
- Mark changes with incomplete tasks as "(In Progress)".
503
-
504
- **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
507
+ Always announce: "Using change: <name>" and how to override (e.g., \`/opsx:apply <other>\`).
505
508
 
506
509
  2. **Check status to understand the schema**
507
510
  \`\`\`bash
@@ -742,7 +745,7 @@ export function getSyncSpecsSkillTemplate() {
742
745
 
743
746
  This is an **agent-driven** operation - you will read delta specs and directly edit main specs to apply the changes. This allows intelligent merging (e.g., adding a scenario without copying the entire requirement).
744
747
 
745
- **Input**: Optionally specify a change name. If omitted, MUST prompt for available changes.
748
+ **Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
746
749
 
747
750
  **Steps**
748
751
 
@@ -879,6 +882,8 @@ export function getOpsxExploreCommandTemplate() {
879
882
  tags: ['workflow', 'explore', 'experimental', 'thinking'],
880
883
  content: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes.
881
884
 
885
+ **IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first (e.g., start a change with \`/opsx:new\` or \`/opsx:ff\`). You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing.
886
+
882
887
  **This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore.
883
888
 
884
889
  **Input**: The argument after \`/opsx:explore\` is whatever the user wants to think about. Could be:
@@ -893,6 +898,7 @@ export function getOpsxExploreCommandTemplate() {
893
898
  ## The Stance
894
899
 
895
900
  - **Curious, not prescriptive** - Ask questions that emerge naturally, don't follow a script
901
+ - **Open threads, not interrogations** - Surface multiple interesting directions and let the user follow what resonates. Don't funnel them through a single path of questions.
896
902
  - **Visual** - Use ASCII diagrams liberally when they'd help clarify thinking
897
903
  - **Adaptive** - Follow interesting threads, pivot when new information emerges
898
904
  - **Patient** - Don't rush to conclusions, let the shape of the problem emerge
@@ -1033,6 +1039,7 @@ When things crystallize, you might offer a summary - but it's optional. Sometime
1033
1039
 
1034
1040
  ## Guardrails
1035
1041
 
1042
+ - **Don't implement** - Never write code or implement features. Creating OpenSpec artifacts is fine, writing application code is not.
1036
1043
  - **Don't fake understanding** - If something is unclear, dig deeper
1037
1044
  - **Don't rush** - Discovery is thinking time, not task time
1038
1045
  - **Don't force structure** - Let patterns emerge naturally
@@ -1127,7 +1134,7 @@ export function getOpsxContinueCommandTemplate() {
1127
1134
  tags: ['workflow', 'artifacts', 'experimental'],
1128
1135
  content: `Continue working on a change by creating the next artifact.
1129
1136
 
1130
- **Input**: Optionally specify \`--change <name>\` after \`/opsx:continue\`. If omitted, MUST prompt for available changes.
1137
+ **Input**: Optionally specify a change name after \`/opsx:continue\` (e.g., \`/opsx:continue add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
1131
1138
 
1132
1139
  **Steps**
1133
1140
 
@@ -1241,19 +1248,18 @@ export function getOpsxApplyCommandTemplate() {
1241
1248
  tags: ['workflow', 'artifacts', 'experimental'],
1242
1249
  content: `Implement tasks from an OpenSpec change.
1243
1250
 
1244
- **Input**: Optionally specify \`--change <name>\` after \`/opsx:apply\`. If omitted, MUST prompt for available changes.
1251
+ **Input**: Optionally specify a change name (e.g., \`/opsx:apply add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
1245
1252
 
1246
1253
  **Steps**
1247
1254
 
1248
- 1. **If no change name provided, prompt for selection**
1255
+ 1. **Select the change**
1249
1256
 
1250
- Run \`openspec list --json\` to get available changes. Use the **AskUserQuestion tool** to let the user select.
1257
+ If a name is provided, use it. Otherwise:
1258
+ - Infer from conversation context if the user mentioned a change
1259
+ - Auto-select if only one active change exists
1260
+ - If ambiguous, run \`openspec list --json\` to get available changes and use the **AskUserQuestion tool** to let the user select
1251
1261
 
1252
- Show changes that are implementation-ready (have tasks artifact).
1253
- Include the schema used for each change if available.
1254
- Mark changes with incomplete tasks as "(In Progress)".
1255
-
1256
- **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
1262
+ Always announce: "Using change: <name>" and how to override (e.g., \`/opsx:apply <other>\`).
1257
1263
 
1258
1264
  2. **Check status to understand the schema**
1259
1265
  \`\`\`bash
@@ -1493,7 +1499,7 @@ export function getArchiveChangeSkillTemplate() {
1493
1499
  description: 'Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.',
1494
1500
  instructions: `Archive a completed change in the experimental workflow.
1495
1501
 
1496
- **Input**: Optionally specify a change name. If omitted, MUST prompt for available changes.
1502
+ **Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
1497
1503
 
1498
1504
  **Steps**
1499
1505
 
@@ -1532,38 +1538,20 @@ export function getArchiveChangeSkillTemplate() {
1532
1538
 
1533
1539
  **If no tasks file exists:** Proceed without task-related warning.
1534
1540
 
1535
- 4. **Check if delta specs need syncing**
1541
+ 4. **Assess delta spec sync state**
1536
1542
 
1537
- Check if \`specs/\` directory exists in the change with spec files.
1543
+ Check for delta specs at \`openspec/changes/<name>/specs/\`. If none exist, proceed without sync prompt.
1538
1544
 
1539
- **If delta specs exist, perform a quick sync check:**
1545
+ **If delta specs exist:**
1546
+ - Compare each delta spec with its corresponding main spec at \`openspec/specs/<capability>/spec.md\`
1547
+ - Determine what changes would be applied (adds, modifications, removals, renames)
1548
+ - Show a combined summary before prompting
1540
1549
 
1541
- a. **For each delta spec** at \`openspec/changes/<name>/specs/<capability>/spec.md\`:
1542
- - Extract requirement names (lines matching \`### Requirement: <name>\`)
1543
- - Note which sections exist (ADDED, MODIFIED, REMOVED)
1550
+ **Prompt options:**
1551
+ - If changes needed: "Sync now (recommended)", "Archive without syncing"
1552
+ - If already synced: "Archive now", "Sync anyway", "Cancel"
1544
1553
 
1545
- b. **Check corresponding main spec** at \`openspec/specs/<capability>/spec.md\`:
1546
- - If main spec doesn't exist → needs sync
1547
- - If main spec exists, check if ADDED requirement names appear in it
1548
- - If any ADDED requirements are missing from main spec → needs sync
1549
-
1550
- c. **Report findings:**
1551
-
1552
- **If sync needed:**
1553
- \`\`\`
1554
- ⚠️ Delta specs may not be synced:
1555
- - specs/auth/spec.md → Main spec missing requirement "Token Refresh"
1556
- - specs/api/spec.md → Main spec doesn't exist yet
1557
-
1558
- Would you like to sync now before archiving?
1559
- \`\`\`
1560
- - Use **AskUserQuestion tool** with options: "Sync now", "Archive without syncing"
1561
- - If user chooses sync, execute /opsx:sync logic (use the openspec-sync-specs skill)
1562
-
1563
- **If already synced (all requirements found):**
1564
- - Proceed without prompting (specs appear to be in sync)
1565
-
1566
- **If no delta specs exist:** Proceed without sync-related checks.
1554
+ If user chooses sync, execute /opsx:sync logic (use the openspec-sync-specs skill). Proceed to archive regardless of choice.
1567
1555
 
1568
1556
  5. **Perform the archive**
1569
1557
 
@@ -1599,7 +1587,7 @@ export function getArchiveChangeSkillTemplate() {
1599
1587
  **Change:** <change-name>
1600
1588
  **Schema:** <schema-name>
1601
1589
  **Archived to:** openspec/changes/archive/YYYY-MM-DD-<name>/
1602
- **Specs:** ✓ Synced to main specs (or "No delta specs" or "⚠️ Not synced")
1590
+ **Specs:** ✓ Synced to main specs (or "No delta specs" or "Sync skipped")
1603
1591
 
1604
1592
  All artifacts complete. All tasks complete.
1605
1593
  \`\`\`
@@ -1611,7 +1599,7 @@ All artifacts complete. All tasks complete.
1611
1599
  - Preserve .openspec.yaml when moving to archive (it moves with the directory)
1612
1600
  - Show clear summary of what happened
1613
1601
  - If sync is requested, use openspec-sync-specs approach (agent-driven)
1614
- - Quick sync check: look for requirement names in delta specs, verify they exist in main specs`
1602
+ - If delta specs exist, always run the sync assessment and show the combined summary before prompting`
1615
1603
  };
1616
1604
  }
1617
1605
  /**
@@ -1627,7 +1615,7 @@ export function getOpsxSyncCommandTemplate() {
1627
1615
 
1628
1616
  This is an **agent-driven** operation - you will read delta specs and directly edit main specs to apply the changes. This allows intelligent merging (e.g., adding a scenario without copying the entire requirement).
1629
1617
 
1630
- **Input**: Optionally specify \`--change <name>\` after \`/opsx:sync\`. If omitted, MUST prompt for available changes.
1618
+ **Input**: Optionally specify a change name after \`/opsx:sync\` (e.g., \`/opsx:sync add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
1631
1619
 
1632
1620
  **Steps**
1633
1621
 
@@ -1762,7 +1750,7 @@ export function getVerifyChangeSkillTemplate() {
1762
1750
  description: 'Verify implementation matches change artifacts. Use when the user wants to validate that implementation is complete, correct, and coherent before archiving.',
1763
1751
  instructions: `Verify that an implementation matches the change artifacts (specs, tasks, design).
1764
1752
 
1765
- **Input**: Optionally specify a change name. If omitted, MUST prompt for available changes.
1753
+ **Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
1766
1754
 
1767
1755
  **Steps**
1768
1756
 
@@ -1930,7 +1918,7 @@ export function getOpsxArchiveCommandTemplate() {
1930
1918
  tags: ['workflow', 'archive', 'experimental'],
1931
1919
  content: `Archive a completed change in the experimental workflow.
1932
1920
 
1933
- **Input**: Optionally specify \`--change <name>\` after \`/opsx:archive\`. If omitted, MUST prompt for available changes.
1921
+ **Input**: Optionally specify a change name after \`/opsx:archive\` (e.g., \`/opsx:archive add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
1934
1922
 
1935
1923
  **Steps**
1936
1924
 
@@ -1969,38 +1957,20 @@ export function getOpsxArchiveCommandTemplate() {
1969
1957
 
1970
1958
  **If no tasks file exists:** Proceed without task-related warning.
1971
1959
 
1972
- 4. **Check if delta specs need syncing**
1973
-
1974
- Check if \`specs/\` directory exists in the change with spec files.
1975
-
1976
- **If delta specs exist, perform a quick sync check:**
1960
+ 4. **Assess delta spec sync state**
1977
1961
 
1978
- a. **For each delta spec** at \`openspec/changes/<name>/specs/<capability>/spec.md\`:
1979
- - Extract requirement names (lines matching \`### Requirement: <name>\`)
1980
- - Note which sections exist (ADDED, MODIFIED, REMOVED)
1962
+ Check for delta specs at \`openspec/changes/<name>/specs/\`. If none exist, proceed without sync prompt.
1981
1963
 
1982
- b. **Check corresponding main spec** at \`openspec/specs/<capability>/spec.md\`:
1983
- - If main spec doesn't exist needs sync
1984
- - If main spec exists, check if ADDED requirement names appear in it
1985
- - If any ADDED requirements are missing from main spec → needs sync
1964
+ **If delta specs exist:**
1965
+ - Compare each delta spec with its corresponding main spec at \`openspec/specs/<capability>/spec.md\`
1966
+ - Determine what changes would be applied (adds, modifications, removals, renames)
1967
+ - Show a combined summary before prompting
1986
1968
 
1987
- c. **Report findings:**
1969
+ **Prompt options:**
1970
+ - If changes needed: "Sync now (recommended)", "Archive without syncing"
1971
+ - If already synced: "Archive now", "Sync anyway", "Cancel"
1988
1972
 
1989
- **If sync needed:**
1990
- \`\`\`
1991
- ⚠️ Delta specs may not be synced:
1992
- - specs/auth/spec.md → Main spec missing requirement "Token Refresh"
1993
- - specs/api/spec.md → Main spec doesn't exist yet
1994
-
1995
- Would you like to sync now before archiving?
1996
- \`\`\`
1997
- - Use **AskUserQuestion tool** with options: "Sync now", "Archive without syncing"
1998
- - If user chooses sync, execute \`/opsx:sync\` logic
1999
-
2000
- **If already synced (all requirements found):**
2001
- - Proceed without prompting (specs appear to be in sync)
2002
-
2003
- **If no delta specs exist:** Proceed without sync-related checks.
1973
+ If user chooses sync, execute \`/opsx:sync\` logic. Proceed to archive regardless of choice.
2004
1974
 
2005
1975
  5. **Perform the archive**
2006
1976
 
@@ -2025,7 +1995,7 @@ export function getOpsxArchiveCommandTemplate() {
2025
1995
  - Change name
2026
1996
  - Schema that was used
2027
1997
  - Archive location
2028
- - Spec sync status (synced / not synced / no delta specs)
1998
+ - Spec sync status (synced / sync skipped / no delta specs)
2029
1999
  - Note about any warnings (incomplete artifacts/tasks)
2030
2000
 
2031
2001
  **Output On Success**
@@ -2062,12 +2032,12 @@ All artifacts complete. All tasks complete.
2062
2032
  **Change:** <change-name>
2063
2033
  **Schema:** <schema-name>
2064
2034
  **Archived to:** openspec/changes/archive/YYYY-MM-DD-<name>/
2065
- **Specs:** ⚠️ Not synced
2035
+ **Specs:** Sync skipped (user chose to skip)
2066
2036
 
2067
2037
  **Warnings:**
2068
2038
  - Archived with 2 incomplete artifacts
2069
2039
  - Archived with 3 incomplete tasks
2070
- - Delta specs were not synced (user chose to skip)
2040
+ - Delta spec sync was skipped (user chose to skip)
2071
2041
 
2072
2042
  Review the archive if this was not intentional.
2073
2043
  \`\`\`
@@ -2093,9 +2063,9 @@ Target archive directory already exists.
2093
2063
  - Use artifact graph (openspec status --json) for completion checking
2094
2064
  - Don't block archive on warnings - just inform and confirm
2095
2065
  - Preserve .openspec.yaml when moving to archive (it moves with the directory)
2096
- - Quick sync check: look for requirement names in delta specs, verify they exist in main specs
2097
2066
  - Show clear summary of what happened
2098
- - If sync is requested, use /opsx:sync approach (agent-driven)`
2067
+ - If sync is requested, use /opsx:sync approach (agent-driven)
2068
+ - If delta specs exist, always run the sync assessment and show the combined summary before prompting`
2099
2069
  };
2100
2070
  }
2101
2071
  /**
@@ -2109,7 +2079,7 @@ export function getOpsxVerifyCommandTemplate() {
2109
2079
  tags: ['workflow', 'verify', 'experimental'],
2110
2080
  content: `Verify that an implementation matches the change artifacts (specs, tasks, design).
2111
2081
 
2112
- **Input**: Optionally specify \`--change <name>\` after \`/opsx:verify\`. If omitted, MUST prompt for available changes.
2082
+ **Input**: Optionally specify a change name after \`/opsx:verify\` (e.g., \`/opsx:verify add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
2113
2083
 
2114
2084
  **Steps**
2115
2085
 
@@ -2266,4 +2236,112 @@ Use clear markdown with:
2266
2236
  - No vague suggestions like "consider reviewing"`
2267
2237
  };
2268
2238
  }
2239
+ /**
2240
+ * Template for feedback skill
2241
+ * For collecting and submitting user feedback with context enrichment
2242
+ */
2243
+ export function getFeedbackSkillTemplate() {
2244
+ return {
2245
+ name: 'feedback',
2246
+ description: 'Collect and submit user feedback about OpenSpec with context enrichment and anonymization.',
2247
+ instructions: `Help the user submit feedback about OpenSpec.
2248
+
2249
+ **Goal**: Guide the user through collecting, enriching, and submitting feedback while ensuring privacy through anonymization.
2250
+
2251
+ **Process**
2252
+
2253
+ 1. **Gather context from the conversation**
2254
+ - Review recent conversation history for context
2255
+ - Identify what task was being performed
2256
+ - Note what worked well or poorly
2257
+ - Capture specific friction points or praise
2258
+
2259
+ 2. **Draft enriched feedback**
2260
+ - Create a clear, descriptive title (single sentence, no "Feedback:" prefix needed)
2261
+ - Write a body that includes:
2262
+ - What the user was trying to do
2263
+ - What happened (good or bad)
2264
+ - Relevant context from the conversation
2265
+ - Any specific suggestions or requests
2266
+
2267
+ 3. **Anonymize sensitive information**
2268
+ - Replace file paths with \`<path>\` or generic descriptions
2269
+ - Replace API keys, tokens, secrets with \`<redacted>\`
2270
+ - Replace company/organization names with \`<company>\`
2271
+ - Replace personal names with \`<user>\`
2272
+ - Replace specific URLs with \`<url>\` unless public/relevant
2273
+ - Keep technical details that help understand the issue
2274
+
2275
+ 4. **Present draft for approval**
2276
+ - Show the complete draft to the user
2277
+ - Display both title and body clearly
2278
+ - Ask for explicit approval before submitting
2279
+ - Allow the user to request modifications
2280
+
2281
+ 5. **Submit on confirmation**
2282
+ - Use the \`openspec feedback\` command to submit
2283
+ - Format: \`openspec feedback "title" --body "body content"\`
2284
+ - The command will automatically add metadata (version, platform, timestamp)
2285
+
2286
+ **Example Draft**
2287
+
2288
+ \`\`\`
2289
+ Title: Error handling in artifact workflow needs improvement
2290
+
2291
+ Body:
2292
+ I was working on creating a new change and encountered an issue with
2293
+ the artifact workflow. When I tried to continue after creating the
2294
+ proposal, the system didn't clearly indicate that I needed to complete
2295
+ the specs first.
2296
+
2297
+ Suggestion: Add clearer error messages that explain dependency chains
2298
+ in the artifact workflow. Something like "Cannot create design.md
2299
+ because specs are not complete (0/2 done)."
2300
+
2301
+ Context: Using the spec-driven schema with <path>/my-project
2302
+ \`\`\`
2303
+
2304
+ **Anonymization Examples**
2305
+
2306
+ Before:
2307
+ \`\`\`
2308
+ Working on /Users/john/mycompany/auth-service/src/oauth.ts
2309
+ Failed with API key: sk_live_abc123xyz
2310
+ Working at Acme Corp
2311
+ \`\`\`
2312
+
2313
+ After:
2314
+ \`\`\`
2315
+ Working on <path>/oauth.ts
2316
+ Failed with API key: <redacted>
2317
+ Working at <company>
2318
+ \`\`\`
2319
+
2320
+ **Guardrails**
2321
+
2322
+ - MUST show complete draft before submitting
2323
+ - MUST ask for explicit approval
2324
+ - MUST anonymize sensitive information
2325
+ - ALLOW user to modify draft before submitting
2326
+ - DO NOT submit without user confirmation
2327
+ - DO include relevant technical context
2328
+ - DO keep conversation-specific insights
2329
+
2330
+ **User Confirmation Required**
2331
+
2332
+ Always ask:
2333
+ \`\`\`
2334
+ Here's the feedback I've drafted:
2335
+
2336
+ Title: [title]
2337
+
2338
+ Body:
2339
+ [body]
2340
+
2341
+ Does this look good? I can modify it if you'd like, or submit it as-is.
2342
+ \`\`\`
2343
+
2344
+ Only proceed with submission after user confirms.`
2345
+ };
2346
+ }
2269
2347
  //# sourceMappingURL=skill-templates.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fission-ai/openspec",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "AI-native system for spec-driven development",
5
5
  "keywords": [
6
6
  "openspec",