@fission-ai/openspec 1.13.0 → 1.13.1

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.
Files changed (102) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/change.js +12 -1
  3. package/dist/commands/config.d.ts +9 -0
  4. package/dist/commands/config.js +161 -22
  5. package/dist/commands/feedback.js +6 -4
  6. package/dist/commands/schema.js +30 -9
  7. package/dist/commands/store.js +5 -2
  8. package/dist/commands/validate.d.ts +7 -0
  9. package/dist/commands/validate.js +63 -1
  10. package/dist/commands/workflow/instructions.js +33 -14
  11. package/dist/commands/workflow/new-change.js +20 -0
  12. package/dist/commands/workflow/shared.js +8 -0
  13. package/dist/commands/workflow/status.d.ts +5 -1
  14. package/dist/commands/workflow/status.js +42 -5
  15. package/dist/core/archive.js +17 -1
  16. package/dist/core/artifact-graph/schema.d.ts +14 -0
  17. package/dist/core/artifact-graph/schema.js +52 -0
  18. package/dist/core/artifact-graph/types.js +12 -1
  19. package/dist/core/change-status-policy.d.ts +14 -0
  20. package/dist/core/change-status-policy.js +14 -6
  21. package/dist/core/command-generation/generator.js +2 -0
  22. package/dist/core/completion-tip.js +7 -7
  23. package/dist/core/completions/installers/bash-installer.js +15 -7
  24. package/dist/core/completions/installers/shell-quote.d.ts +11 -0
  25. package/dist/core/completions/installers/shell-quote.js +13 -0
  26. package/dist/core/completions/installers/zsh-installer.js +3 -2
  27. package/dist/core/config-schema.d.ts +1 -1
  28. package/dist/core/config.d.ts +16 -0
  29. package/dist/core/config.js +27 -1
  30. package/dist/core/global-config.d.ts +30 -2
  31. package/dist/core/global-config.js +57 -3
  32. package/dist/core/init.js +13 -3
  33. package/dist/core/legacy-cleanup.d.ts +4 -0
  34. package/dist/core/legacy-cleanup.js +180 -12
  35. package/dist/core/list.js +55 -11
  36. package/dist/core/migration.js +6 -1
  37. package/dist/core/parsers/change-parser.d.ts +12 -1
  38. package/dist/core/parsers/change-parser.js +85 -87
  39. package/dist/core/parsers/markdown-parser.js +4 -3
  40. package/dist/core/parsers/requirement-blocks.d.ts +44 -3
  41. package/dist/core/parsers/requirement-blocks.js +90 -15
  42. package/dist/core/parsers/requirement-text.d.ts +13 -2
  43. package/dist/core/parsers/requirement-text.js +34 -7
  44. package/dist/core/parsers/spec-structure.js +4 -1
  45. package/dist/core/project-config.d.ts +9 -1
  46. package/dist/core/project-config.js +11 -2
  47. package/dist/core/references.d.ts +20 -0
  48. package/dist/core/references.js +56 -0
  49. package/dist/core/shared/skill-content-equivalence.js +5 -1
  50. package/dist/core/shared/skill-generation.js +36 -8
  51. package/dist/core/shared/tool-detection.js +9 -3
  52. package/dist/core/specs-apply.js +82 -11
  53. package/dist/core/store/git.d.ts +33 -0
  54. package/dist/core/store/git.js +60 -6
  55. package/dist/core/store/operations.d.ts +1 -1
  56. package/dist/core/store/operations.js +32 -10
  57. package/dist/core/store/registry.d.ts +2 -1
  58. package/dist/core/store/registry.js +5 -1
  59. package/dist/core/templates/optional-workflow.d.ts +69 -0
  60. package/dist/core/templates/optional-workflow.js +140 -0
  61. package/dist/core/templates/workflows/apply-change.js +18 -3
  62. package/dist/core/templates/workflows/archive-change.js +50 -15
  63. package/dist/core/templates/workflows/bulk-archive-change.js +63 -13
  64. package/dist/core/templates/workflows/continue-change.js +14 -2
  65. package/dist/core/templates/workflows/explore.js +32 -14
  66. package/dist/core/templates/workflows/ff-change.js +19 -3
  67. package/dist/core/templates/workflows/new-change.js +15 -3
  68. package/dist/core/templates/workflows/onboard.js +67 -37
  69. package/dist/core/templates/workflows/project-root.d.ts +29 -0
  70. package/dist/core/templates/workflows/project-root.js +38 -0
  71. package/dist/core/templates/workflows/propose.js +22 -5
  72. package/dist/core/templates/workflows/sync-specs.js +40 -1
  73. package/dist/core/templates/workflows/update-change.js +52 -25
  74. package/dist/core/templates/workflows/verify-change.js +12 -3
  75. package/dist/core/update.d.ts +12 -0
  76. package/dist/core/update.js +58 -3
  77. package/dist/core/validation/task-checkboxes.d.ts +34 -0
  78. package/dist/core/validation/task-checkboxes.js +181 -0
  79. package/dist/core/validation/validator.d.ts +53 -1
  80. package/dist/core/validation/validator.js +154 -40
  81. package/dist/core/version-check.d.ts +14 -7
  82. package/dist/core/version-check.js +63 -17
  83. package/dist/core/worksets.js +6 -4
  84. package/dist/prompts/searchable-multi-select.d.ts +7 -0
  85. package/dist/prompts/searchable-multi-select.js +35 -6
  86. package/dist/telemetry/config.js +14 -2
  87. package/dist/telemetry/index.d.ts +4 -3
  88. package/dist/telemetry/index.js +22 -10
  89. package/dist/telemetry/opt-out.d.ts +17 -0
  90. package/dist/telemetry/opt-out.js +27 -0
  91. package/dist/utils/nested-change.d.ts +35 -0
  92. package/dist/utils/nested-change.js +186 -0
  93. package/dist/utils/spec-discovery.d.ts +20 -0
  94. package/dist/utils/spec-discovery.js +59 -0
  95. package/dist/utils/task-progress.d.ts +1 -1
  96. package/dist/utils/task-progress.js +38 -6
  97. package/package.json +4 -4
  98. package/schemas/spec-driven/schema.yaml +10 -3
  99. package/schemas/spec-driven/templates/design.md +2 -0
  100. package/schemas/spec-driven/templates/proposal.md +2 -0
  101. package/schemas/spec-driven/templates/spec.md +2 -0
  102. package/schemas/spec-driven/templates/tasks.md +2 -0
@@ -1,8 +1,53 @@
1
+ import { onlyWithWorkflow, optionalWorkflow } from '../optional-workflow.js';
1
2
  import { STORE_SELECTION_GUIDANCE } from './store-selection.js';
3
+ import { PROJECT_ROOT_GUARD } from './project-root.js';
4
+ /**
5
+ * The tutorial names other workflows throughout. Which of them exist depends
6
+ * on the profile, so each mention is resolved at generation time (see
7
+ * optional-workflow.ts) instead of being listed with an "if installed" caveat
8
+ * the reader has to check for themselves.
9
+ */
10
+ const EXPLORE_MODE_NOTE = optionalWorkflow('explore', 'Explore mode (`/opsx:explore`) is for this kind of thinking—investigating before implementing. You can use it anytime you need to think through a problem.', 'Investigating before implementing is worth doing whenever a problem needs thinking through.');
11
+ /**
12
+ * The command-reference tables. Every row is dropped along with its line when
13
+ * the profile does not install that workflow, so the table lists exactly the
14
+ * commands the reader can run — and stays a valid table either way.
15
+ */
16
+ const COMMAND_REFERENCE_ROWS = [
17
+ onlyWithWorkflow('propose', ' | `/opsx:propose` | Create a change and generate all artifacts |'),
18
+ onlyWithWorkflow('explore', ' | `/opsx:explore` | Think through problems before/during work |'),
19
+ onlyWithWorkflow('apply', ' | `/opsx:apply` | Implement tasks from a change |'),
20
+ onlyWithWorkflow('archive', ' | `/opsx:archive` | Archive a completed change |'),
21
+ onlyWithWorkflow('new', ' | `/opsx:new` | Start a new change, one artifact at a time |'),
22
+ onlyWithWorkflow('continue', ' | `/opsx:continue` | Continue working on an existing change |'),
23
+ onlyWithWorkflow('ff', ' | `/opsx:ff` | Fast-forward: create all artifacts at once |'),
24
+ onlyWithWorkflow('verify', ' | `/opsx:verify` | Verify implementation matches artifacts |'),
25
+ ].join('\n');
26
+ const QUICK_REFERENCE_ROWS = [
27
+ onlyWithWorkflow('propose', ' | `/opsx:propose <name>` | Create a change and generate all artifacts |'),
28
+ onlyWithWorkflow('explore', ' | `/opsx:explore` | Think through problems (no code changes) |'),
29
+ onlyWithWorkflow('apply', ' | `/opsx:apply <name>` | Implement tasks |'),
30
+ onlyWithWorkflow('archive', ' | `/opsx:archive <name>` | Archive when done |'),
31
+ onlyWithWorkflow('new', ' | `/opsx:new <name>` | Start a new change, step by step |'),
32
+ onlyWithWorkflow('continue', ' | `/opsx:continue <name>` | Continue an existing change |'),
33
+ onlyWithWorkflow('ff', ' | `/opsx:ff <name>` | Fast-forward: all artifacts at once |'),
34
+ onlyWithWorkflow('verify', ' | `/opsx:verify <name>` | Verify implementation |'),
35
+ ].join('\n');
36
+ /**
37
+ * Resume hints for a user stopping mid-tutorial. Both are optional, so the
38
+ * sentence that introduces them stands on its own without either.
39
+ */
40
+ const RESUME_HINTS = [
41
+ onlyWithWorkflow('continue', '- `/opsx:continue <name>` - Resume artifact creation'),
42
+ onlyWithWorkflow('apply', '- `/opsx:apply <name>` - Jump to implementation (if tasks exist)'),
43
+ ].join('\n');
44
+ /** Where the tutorial points once it is over. */
45
+ const NEXT_STEP_INVITE = optionalWorkflow('propose', 'Try `/opsx:propose` on something you actually want to build. You\'ve got the rhythm now!', 'Try this on something you actually want to build. You\'ve got the rhythm now!');
46
+ const QUICK_REFERENCE_INVITE = optionalWorkflow('propose', 'Try `/opsx:propose` to start your first change.', 'Ask me to start your first change whenever you are ready.');
2
47
  export function getOnboardSkillTemplate() {
3
48
  return {
4
49
  name: 'openspec-onboard',
5
- description: 'Guided onboarding for OpenSpec - walk through a complete workflow cycle with narration and real codebase work.',
50
+ description: 'Guided onboarding for OpenSpec - walk through a complete workflow cycle with narration and real codebase work. Also use when the user says "openspec onboard" or "opsx onboard".',
6
51
  instructions: getOnboardInstructions(),
7
52
  license: 'MIT',
8
53
  compatibility: 'Requires openspec CLI.',
@@ -14,6 +59,8 @@ function getOnboardInstructions() {
14
59
 
15
60
  ${STORE_SELECTION_GUIDANCE}
16
61
 
62
+ ${PROJECT_ROOT_GUARD}
63
+
17
64
  ---
18
65
 
19
66
  ## Preflight
@@ -155,7 +202,7 @@ Spend 1-2 minutes investigating the relevant code:
155
202
  │ [Optional: ASCII diagram if helpful] │
156
203
  └─────────────────────────────────────────┘
157
204
 
158
- Explore mode (\`/opsx:explore\`) is for this kind of thinking—investigating before implementing. You can use it anytime you need to think through a problem.
205
+ ${EXPLORE_MODE_NOTE}
159
206
 
160
207
  Now let's create a change to hold our work.
161
208
  \`\`\`
@@ -221,6 +268,8 @@ Here's a draft proposal:
221
268
 
222
269
  ---
223
270
 
271
+ # Proposal
272
+
224
273
  ## Why
225
274
 
226
275
  [1-2 sentences explaining the problem/opportunity]
@@ -288,6 +337,8 @@ Here's the spec:
288
337
 
289
338
  ---
290
339
 
340
+ # Spec Delta
341
+
291
342
  ## ADDED Requirements
292
343
 
293
344
  ### Requirement: <Name>
@@ -327,6 +378,8 @@ Here's the design:
327
378
 
328
379
  ---
329
380
 
381
+ # Design
382
+
330
383
  ## Context
331
384
 
332
385
  [Brief context about the current state]
@@ -372,6 +425,8 @@ Here are the implementation tasks:
372
425
 
373
426
  ---
374
427
 
428
+ # Tasks
429
+
375
430
  ## 1. [Category or file]
376
431
 
377
432
  - [ ] 1.1 [Specific task] — verify: [test, command, observable behavior, or delivered artifact]
@@ -473,29 +528,17 @@ This same rhythm works for any size change—a small fix or a major feature.
473
528
 
474
529
  ## Command Reference
475
530
 
476
- **Core workflow:**
531
+ **The commands you have installed:**
477
532
 
478
- | Command | What it does |
479
- |-------------------|--------------------------------------------|
480
- | \`/opsx:propose\` | Create a change and generate all artifacts |
481
- | \`/opsx:explore\` | Think through problems before/during work |
482
- | \`/opsx:apply\` | Implement tasks from a change |
483
- | \`/opsx:archive\` | Archive a completed change |
484
-
485
- **Additional commands** (only if installed - availability depends on your profile):
486
-
487
- | Command | What it does |
488
- |--------------------|----------------------------------------------------------|
489
- | \`/opsx:new\` | Start a new change, step through artifacts one at a time |
490
- | \`/opsx:continue\` | Continue working on an existing change |
491
- | \`/opsx:ff\` | Fast-forward: create all artifacts at once |
492
- | \`/opsx:verify\` | Verify implementation matches artifacts |
533
+ | Command | What it does |
534
+ |------------------|--------------------------------------------|
535
+ ${COMMAND_REFERENCE_ROWS}
493
536
 
494
537
  ---
495
538
 
496
539
  ## What's Next?
497
540
 
498
- Try \`/opsx:propose\` on something you actually want to build. You've got the rhythm now!
541
+ ${NEXT_STEP_INVITE}
499
542
  \`\`\`
500
543
 
501
544
  ---
@@ -509,9 +552,8 @@ If the user says they need to stop, want to pause, or seem disengaged:
509
552
  \`\`\`
510
553
  No problem! Your change is saved at the \`changeRoot\` reported by \`openspec status --change "<name>" --json\`.
511
554
 
512
- To pick up where we left off later:
513
- - \`/opsx:continue <name>\` - Resume artifact creation (if installed; otherwise \`openspec status --change "<name>" --json\` shows the next artifact)
514
- - \`/opsx:apply <name>\` - Jump to implementation (if tasks exist)
555
+ To pick up where we left off later, \`openspec status --change "<name>" --json\` shows exactly where the change stands.
556
+ ${RESUME_HINTS}
515
557
 
516
558
  The work won't be lost. Come back whenever you're ready.
517
559
  \`\`\`
@@ -525,25 +567,13 @@ If the user says they just want to see the commands or skip the tutorial:
525
567
  \`\`\`
526
568
  ## OpenSpec Quick Reference
527
569
 
528
- **Core workflow:**
570
+ **The commands you have installed:**
529
571
 
530
572
  | Command | What it does |
531
573
  |--------------------------|--------------------------------------------|
532
- | \`/opsx:propose <name>\` | Create a change and generate all artifacts |
533
- | \`/opsx:explore\` | Think through problems (no code changes) |
534
- | \`/opsx:apply <name>\` | Implement tasks |
535
- | \`/opsx:archive <name>\` | Archive when done |
536
-
537
- **Additional commands** (only if installed - availability depends on your profile):
538
-
539
- | Command | What it does |
540
- |---------------------------|-------------------------------------|
541
- | \`/opsx:new <name>\` | Start a new change, step by step |
542
- | \`/opsx:continue <name>\` | Continue an existing change |
543
- | \`/opsx:ff <name>\` | Fast-forward: all artifacts at once |
544
- | \`/opsx:verify <name>\` | Verify implementation |
574
+ ${QUICK_REFERENCE_ROWS}
545
575
 
546
- Try \`/opsx:propose\` to start your first change.
576
+ ${QUICK_REFERENCE_INVITE}
547
577
  \`\`\`
548
578
 
549
579
  Exit gracefully.
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Shared project-root guidance for skill template workflows.
3
+ *
4
+ * Generated skills and commands are installed once per machine, so they are
5
+ * offered in every repository the agent opens - including repositories that
6
+ * never ran `openspec init`. Nothing stops the workflow there: `openspec new
7
+ * change` falls back to an implicit root and creates `openspec/` in whatever
8
+ * directory the agent happens to be in.
9
+ *
10
+ * This guidance is interpolated into every workflow so the agent checks for a
11
+ * root before writing. `openspec list --json` is the check because it refuses
12
+ * to fabricate an implicit root: it reports `root: null` both when nothing is
13
+ * set up and when only stores are registered.
14
+ *
15
+ * What follows the check depends on how the workflow was reached, because the
16
+ * two cases want opposite things (#1645). A skill the model picked on its own
17
+ * in an unrelated repository must get out of the way: the user asked for help,
18
+ * not for OpenSpec, and answering with a setup menu is the reported bug. A
19
+ * user who named OpenSpec, named the skill, or ran its slash command is owed
20
+ * an answer about OpenSpec, so that case stops and asks.
21
+ *
22
+ * One text serves both surfaces. `apply-change` and `onboard` render a single
23
+ * body into the skill and the command alike, so a command-only variant would
24
+ * mean threading a surface flag through bodies that deliberately have none.
25
+ * The bullets scope themselves instead: a slash command is an explicit
26
+ * invocation, so its branch is the only one that can apply there.
27
+ */
28
+ export declare const PROJECT_ROOT_GUARD = "**Project check:** These steps expect a project that already uses OpenSpec. Before the first step that writes anything (`new change`, `archive`, `sync specs`, or authoring an artifact file), confirm the project has a root: run `openspec list --json` (with `--store <id>` when a store is selected, since the store is then the root) and read `root`. A root object means the project is set up. `\"root\": null` means it is not - there is no `openspec/` directory here, and a write such as `openspec new change` would create one as a side effect. The command also exits non-zero, which is that answer rather than a broken CLI, so read the JSON instead of retrying or working around it.\n\nOne `\"root\": null` is not about setup: when a `status` error message starts with `Declared in` or `Invalid store declaration in` and names this project's `openspec/config.yaml` (or `config.yml`), the project does use OpenSpec through a store it declares, which this machine cannot resolve (the store is not registered, or the `store:` line is malformed). Do not treat it as uninitialized and skip the branches below: stop before writing and show the user that error's `message` and `fix`.\n\nOtherwise, with no root, what happens next depends on how this workflow was reached:\n\n- **Auto-selected**: you chose this workflow yourself, without the user naming OpenSpec, naming this skill, or running its slash command. Stop using OpenSpec and answer the request normally, as you would with no OpenSpec installed. Do not ask them to set anything up and do not mention OpenSpec setup.\n- **Explicit OpenSpec request**: the user named OpenSpec, named this skill, or ran its slash command. Stop before writing and ask how to proceed: set this project up (`openspec init`), target a store they already have (`--store <id>`), or continue without OpenSpec for this request. Wait for their answer.\n\nIn both branches, never create the root as a side effect: do not run `openspec init` until the user asks for it, do not hand-create `openspec/` files, and do not let a command create it.";
29
+ //# sourceMappingURL=project-root.d.ts.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Shared project-root guidance for skill template workflows.
3
+ *
4
+ * Generated skills and commands are installed once per machine, so they are
5
+ * offered in every repository the agent opens - including repositories that
6
+ * never ran `openspec init`. Nothing stops the workflow there: `openspec new
7
+ * change` falls back to an implicit root and creates `openspec/` in whatever
8
+ * directory the agent happens to be in.
9
+ *
10
+ * This guidance is interpolated into every workflow so the agent checks for a
11
+ * root before writing. `openspec list --json` is the check because it refuses
12
+ * to fabricate an implicit root: it reports `root: null` both when nothing is
13
+ * set up and when only stores are registered.
14
+ *
15
+ * What follows the check depends on how the workflow was reached, because the
16
+ * two cases want opposite things (#1645). A skill the model picked on its own
17
+ * in an unrelated repository must get out of the way: the user asked for help,
18
+ * not for OpenSpec, and answering with a setup menu is the reported bug. A
19
+ * user who named OpenSpec, named the skill, or ran its slash command is owed
20
+ * an answer about OpenSpec, so that case stops and asks.
21
+ *
22
+ * One text serves both surfaces. `apply-change` and `onboard` render a single
23
+ * body into the skill and the command alike, so a command-only variant would
24
+ * mean threading a surface flag through bodies that deliberately have none.
25
+ * The bullets scope themselves instead: a slash command is an explicit
26
+ * invocation, so its branch is the only one that can apply there.
27
+ */
28
+ export const PROJECT_ROOT_GUARD = `**Project check:** These steps expect a project that already uses OpenSpec. Before the first step that writes anything (\`new change\`, \`archive\`, \`sync specs\`, or authoring an artifact file), confirm the project has a root: run \`openspec list --json\` (with \`--store <id>\` when a store is selected, since the store is then the root) and read \`root\`. A root object means the project is set up. \`"root": null\` means it is not - there is no \`openspec/\` directory here, and a write such as \`openspec new change\` would create one as a side effect. The command also exits non-zero, which is that answer rather than a broken CLI, so read the JSON instead of retrying or working around it.
29
+
30
+ One \`"root": null\` is not about setup: when a \`status\` error message starts with \`Declared in\` or \`Invalid store declaration in\` and names this project's \`openspec/config.yaml\` (or \`config.yml\`), the project does use OpenSpec through a store it declares, which this machine cannot resolve (the store is not registered, or the \`store:\` line is malformed). Do not treat it as uninitialized and skip the branches below: stop before writing and show the user that error's \`message\` and \`fix\`.
31
+
32
+ Otherwise, with no root, what happens next depends on how this workflow was reached:
33
+
34
+ - **Auto-selected**: you chose this workflow yourself, without the user naming OpenSpec, naming this skill, or running its slash command. Stop using OpenSpec and answer the request normally, as you would with no OpenSpec installed. Do not ask them to set anything up and do not mention OpenSpec setup.
35
+ - **Explicit OpenSpec request**: the user named OpenSpec, named this skill, or ran its slash command. Stop before writing and ask how to proceed: set this project up (\`openspec init\`), target a store they already have (\`--store <id>\`), or continue without OpenSpec for this request. Wait for their answer.
36
+
37
+ In both branches, never create the root as a side effect: do not run \`openspec init\` until the user asks for it, do not hand-create \`openspec/\` files, and do not let a command create it.`;
38
+ //# sourceMappingURL=project-root.js.map
@@ -1,8 +1,21 @@
1
+ import { optionalWorkflow } from '../optional-workflow.js';
1
2
  import { STORE_SELECTION_GUIDANCE } from './store-selection.js';
3
+ import { PROJECT_ROOT_GUARD } from './project-root.js';
4
+ /**
5
+ * The implementation handoff. `apply` is not guaranteed to be installed, so
6
+ * the prompt is resolved at generation time (see optional-workflow.ts) rather
7
+ * than naming a workflow that may not exist.
8
+ *
9
+ * The two surfaces word this differently on purpose (#258): a command-only
10
+ * tool has no conversational agent to ask, so its prompt names a command or
11
+ * the CLI and never invites "ask me to implement".
12
+ */
13
+ const SKILL_APPLY_HANDOFF = optionalWorkflow('apply', 'run `/opsx:apply` or ask me to apply this change', 'ask me to apply this change');
14
+ const COMMAND_APPLY_HANDOFF = optionalWorkflow('apply', 'run `/opsx:apply`', 'run `openspec instructions apply --change "<name>" --json` to get the tasks');
2
15
  export function getOpsxProposeSkillTemplate() {
3
16
  return {
4
17
  name: 'openspec-propose',
5
- description: 'Propose a new change with all artifacts generated in one step. Use when the user wants to quickly describe what they want to build and get a complete proposal with design, specs, and tasks ready for implementation.',
18
+ description: 'Propose a new OpenSpec change with all artifacts generated in one step. Use when the user wants to quickly describe what they want to build and get a complete proposal with design, specs, and tasks ready for implementation. Also use when the user says "openspec propose" or "opsx propose".',
6
19
  instructions: `Propose a new change - create the change and generate all artifacts in one step.
7
20
 
8
21
  **Planning boundary**: This workflow creates planning artifacts only. The user request that selected or triggered this workflow authorizes planning only, even if it asks to build or fix something. Do not edit project code. After the planning artifacts are complete, stop. Do not start implementation in the same response, even if the initial request asks for it. Wait for a new user request after the artifacts are presented; then start the apply workflow.
@@ -21,6 +34,8 @@ When the user is ready to implement, they must start the apply workflow explicit
21
34
 
22
35
  ${STORE_SELECTION_GUIDANCE}
23
36
 
37
+ ${PROJECT_ROOT_GUARD}
38
+
24
39
  **Input**: The user's request should include a change name (kebab-case) OR a description of what they want to build.
25
40
 
26
41
  **Steps**
@@ -38,7 +53,7 @@ ${STORE_SELECTION_GUIDANCE}
38
53
 
39
54
  2. **Load project context**
40
55
 
41
- Run \`openspec context --json\` from the current working directory (or \`openspec context --json --store "<store-id>"\` when a registered store was explicitly selected). Use the returned \`root.path\` as the authoritative OpenSpec root. If context reports \`no_openspec_root\`, stop without creating or changing any files. Offer \`openspec init\` and wait for the user to request initialization. Do not initialize automatically or run \`openspec new change\`. After initialization, rerun this context check before continuing. For any other context failure, stop and report the error; do not fall back to the current directory or run later OpenSpec commands without the selected store.
56
+ Run \`openspec context --json\` from the current working directory (or \`openspec context --json --store "<store-id>"\` when a registered store was explicitly selected). Use the returned \`root.path\` as the authoritative OpenSpec root. If context reports \`no_openspec_root\`, stop without creating or changing any files and follow the **Project check** above for how this workflow was reached. Offer \`openspec init\` only for an explicit OpenSpec request, and wait for the user to request initialization. Do not initialize automatically or run \`openspec new change\`. After initialization, rerun this context check before continuing. For any other context failure, stop and report the error; do not fall back to the current directory or run later OpenSpec commands without the selected store.
42
57
 
43
58
  Only when context returns a resolved \`root.path\`, read \`<root.path>/openspec/config.yaml\`. Use \`config.yml\` only when \`config.yaml\` does not exist. If neither file exists, continue without project context. Do not fall back to \`config.yml\` if \`config.yaml\` is unreadable or invalid.
44
59
 
@@ -134,7 +149,7 @@ After completing all artifacts, summarize:
134
149
  - Change name and location
135
150
  - List of artifacts created with brief descriptions, plus any conditional artifact you skipped and why
136
151
  - What's ready: "All artifacts needed for implementation are ready."
137
- - Prompt: "The artifacts are ready for review. When you are ready, run \`/opsx:apply\` or ask me to apply this change."
152
+ - Prompt: "The artifacts are ready for review. When you are ready, ${SKILL_APPLY_HANDOFF}."
138
153
 
139
154
  **Artifact Creation Guidelines**
140
155
 
@@ -183,6 +198,8 @@ When the user is ready to implement, they must start the apply workflow explicit
183
198
 
184
199
  ${STORE_SELECTION_GUIDANCE}
185
200
 
201
+ ${PROJECT_ROOT_GUARD}
202
+
186
203
  **Input**: The argument after \`/opsx:propose\` is the change name (kebab-case), OR a description of what the user wants to build.
187
204
 
188
205
  **Steps**
@@ -200,7 +217,7 @@ ${STORE_SELECTION_GUIDANCE}
200
217
 
201
218
  2. **Load project context**
202
219
 
203
- Run \`openspec context --json\` from the current working directory (or \`openspec context --json --store "<store-id>"\` when a registered store was explicitly selected). Use the returned \`root.path\` as the authoritative OpenSpec root. If context reports \`no_openspec_root\`, stop without creating or changing any files. Offer \`openspec init\` and wait for the user to request initialization. Do not initialize automatically or run \`openspec new change\`. After initialization, rerun this context check before continuing. For any other context failure, stop and report the error; do not fall back to the current directory or run later OpenSpec commands without the selected store.
220
+ Run \`openspec context --json\` from the current working directory (or \`openspec context --json --store "<store-id>"\` when a registered store was explicitly selected). Use the returned \`root.path\` as the authoritative OpenSpec root. If context reports \`no_openspec_root\`, stop without creating or changing any files and follow the **Project check** above for how this workflow was reached. Offer \`openspec init\` only for an explicit OpenSpec request, and wait for the user to request initialization. Do not initialize automatically or run \`openspec new change\`. After initialization, rerun this context check before continuing. For any other context failure, stop and report the error; do not fall back to the current directory or run later OpenSpec commands without the selected store.
204
221
 
205
222
  Only when context returns a resolved \`root.path\`, read \`<root.path>/openspec/config.yaml\`. Use \`config.yml\` only when \`config.yaml\` does not exist. If neither file exists, continue without project context. Do not fall back to \`config.yml\` if \`config.yaml\` is unreadable or invalid.
206
223
 
@@ -296,7 +313,7 @@ After completing all artifacts, summarize:
296
313
  - Change name and location
297
314
  - List of artifacts created with brief descriptions, plus any conditional artifact you skipped and why
298
315
  - What's ready: "All artifacts needed for implementation are ready."
299
- - Prompt: "The artifacts are ready for review. When you are ready, run \`/opsx:apply\`."
316
+ - Prompt: "The artifacts are ready for review. When you are ready, ${COMMAND_APPLY_HANDOFF}."
300
317
 
301
318
  **Artifact Creation Guidelines**
302
319
 
@@ -1,14 +1,17 @@
1
1
  import { STORE_SELECTION_GUIDANCE } from './store-selection.js';
2
+ import { PROJECT_ROOT_GUARD } from './project-root.js';
2
3
  export function getSyncSpecsSkillTemplate() {
3
4
  return {
4
5
  name: 'openspec-sync-specs',
5
- description: 'Sync delta specs from a change to main specs. Use when the user wants to update main specs with changes from a delta spec, without archiving the change.',
6
+ description: 'Sync delta specs from an OpenSpec change to main specs. Use when the user wants to update main specs with changes from a delta spec, without archiving the change. Also use when the user says "openspec sync" or "opsx sync".',
6
7
  instructions: `Sync delta specs from a change to main specs.
7
8
 
8
9
  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).
9
10
 
10
11
  ${STORE_SELECTION_GUIDANCE}
11
12
 
13
+ ${PROJECT_ROOT_GUARD}
14
+
12
15
  \`<capability-path>\` is the spec directory relative to \`specs/\` (for example, \`user-auth\` or \`identity/user-auth\`). Preserve the full path from each delta spec when resolving its main spec.
13
16
 
14
17
  **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.
@@ -89,6 +92,13 @@ ${STORE_SELECTION_GUIDANCE}
89
92
 
90
93
  b. **Read the main spec** at \`<planningHome.root>/openspec/specs/<capability-path>/spec.md\` (may not exist yet)
91
94
 
95
+ **If it does not exist yet** (a new capability), match what \`openspec archive\` does:
96
+ only ADDED requirements may be applied - step d creates the spec from them.
97
+ MODIFIED and RENAMED have no requirement to act on, so stop the sync for that
98
+ capability and report that its main spec does not exist and only ADDED is allowed
99
+ for a new spec; never invent the missing requirement. REMOVED has nothing to
100
+ remove - skip it and warn.
101
+
92
102
  c. **Apply changes intelligently**:
93
103
 
94
104
  **ADDED Requirements:**
@@ -136,6 +146,14 @@ ${STORE_SELECTION_GUIDANCE}
136
146
  (this is what \`openspec archive\` does; it warns and moves on)
137
147
 
138
148
  d. **Create new main spec** if capability doesn't exist yet:
149
+ - Only when the delta has ADDED requirements to put in it and no MODIFIED or
150
+ RENAMED requirements blocked this capability in step b. Otherwise create nothing
151
+ and leave the specs directory untouched. For a REMOVED-only delta, if the change's
152
+ \`.openspec.yaml\` declares \`retire_capabilities: true\`, report it as already retired
153
+ and continue without recreating the spec. Without that marker, report the sync as blocked:
154
+ \`openspec archive\` rejects it with \`Spec must have at least one requirement\`.
155
+ An empty delta has no operations to sync; report it as blocked too.
156
+ Never write an empty \`## Requirements\` section.
139
157
  - Create \`<planningHome.root>/openspec/specs/<capability-path>/spec.md\`
140
158
  - Add Purpose section: copy the delta's \`## Purpose\` body verbatim when it has one
141
159
  (this is what \`openspec archive\` does); only write a brief TBD placeholder when it does not
@@ -160,6 +178,8 @@ ${STORE_SELECTION_GUIDANCE}
160
178
  **Delta Spec Format Reference**
161
179
 
162
180
  \`\`\`markdown
181
+ # Spec Delta
182
+
163
183
  ## Purpose
164
184
 
165
185
  Only on a delta that introduces a brand-new capability. Seeds the new main spec.
@@ -270,6 +290,8 @@ This is an **agent-driven** operation - you will read delta specs and directly e
270
290
 
271
291
  ${STORE_SELECTION_GUIDANCE}
272
292
 
293
+ ${PROJECT_ROOT_GUARD}
294
+
273
295
  \`<capability-path>\` is the spec directory relative to \`specs/\` (for example, \`user-auth\` or \`identity/user-auth\`). Preserve the full path from each delta spec when resolving its main spec.
274
296
 
275
297
  **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.
@@ -350,6 +372,13 @@ ${STORE_SELECTION_GUIDANCE}
350
372
 
351
373
  b. **Read the main spec** at \`<planningHome.root>/openspec/specs/<capability-path>/spec.md\` (may not exist yet)
352
374
 
375
+ **If it does not exist yet** (a new capability), match what \`openspec archive\` does:
376
+ only ADDED requirements may be applied - step d creates the spec from them.
377
+ MODIFIED and RENAMED have no requirement to act on, so stop the sync for that
378
+ capability and report that its main spec does not exist and only ADDED is allowed
379
+ for a new spec; never invent the missing requirement. REMOVED has nothing to
380
+ remove - skip it and warn.
381
+
353
382
  c. **Apply changes intelligently**:
354
383
 
355
384
  **ADDED Requirements:**
@@ -397,6 +426,14 @@ ${STORE_SELECTION_GUIDANCE}
397
426
  (this is what \`openspec archive\` does; it warns and moves on)
398
427
 
399
428
  d. **Create new main spec** if capability doesn't exist yet:
429
+ - Only when the delta has ADDED requirements to put in it and no MODIFIED or
430
+ RENAMED requirements blocked this capability in step b. Otherwise create nothing
431
+ and leave the specs directory untouched. For a REMOVED-only delta, if the change's
432
+ \`.openspec.yaml\` declares \`retire_capabilities: true\`, report it as already retired
433
+ and continue without recreating the spec. Without that marker, report the sync as blocked:
434
+ \`openspec archive\` rejects it with \`Spec must have at least one requirement\`.
435
+ An empty delta has no operations to sync; report it as blocked too.
436
+ Never write an empty \`## Requirements\` section.
400
437
  - Create \`<planningHome.root>/openspec/specs/<capability-path>/spec.md\`
401
438
  - Add Purpose section: copy the delta's \`## Purpose\` body verbatim when it has one
402
439
  (this is what \`openspec archive\` does); only write a brief TBD placeholder when it does not
@@ -421,6 +458,8 @@ ${STORE_SELECTION_GUIDANCE}
421
458
  **Delta Spec Format Reference**
422
459
 
423
460
  \`\`\`markdown
461
+ # Spec Delta
462
+
424
463
  ## Purpose
425
464
 
426
465
  Only on a delta that introduces a brand-new capability. Seeds the new main spec.
@@ -1,15 +1,38 @@
1
+ import { optionalWorkflow } from '../optional-workflow.js';
1
2
  import { STORE_SELECTION_GUIDANCE } from './store-selection.js';
3
+ import { PROJECT_ROOT_GUARD } from './project-root.js';
4
+ /**
5
+ * Passages that hand off to `/opsx:continue` or `/opsx:new`. Neither workflow
6
+ * is in the `core` profile, so each is authored with a CLI fallback and
7
+ * resolved at generation time (see optional-workflow.ts). Shared by both
8
+ * surfaces below so the skill and the command cannot drift apart.
9
+ */
10
+ const CONTINUE_SCOPE_NOTE = optionalWorkflow('continue', 'This workflow revises artifacts that already exist; `/opsx:continue` is what creates the ones that do not.', 'This workflow revises artifacts that already exist; it never creates missing ones. When an artifact is missing, `openspec status --change "<name>" --json` names the next one and `openspec instructions "<artifact-id>" --change "<name>" --json` explains how to write it.');
11
+ const CONTINUE_CREATE_THEM = optionalWorkflow('continue', 'point the user to `/opsx:continue` to create them', 'point the user to `openspec instructions "<artifact-id>" --change "<name>" --json` for how to create them');
12
+ const CONTINUE_NEXT_STEP = optionalWorkflow('continue', 'suggest `/opsx:continue` to create them', 'run `openspec status --change "<name>" --json` for the next artifact and point the user to `openspec instructions "<artifact-id>" --change "<name>" --json` for how to create it');
13
+ const CONTINUE_DEFERRED = optionalWorkflow('continue', 'Anything deferred to `/opsx:continue` (not-yet-created artifacts or files)', 'Anything deferred because it does not exist yet (not-yet-created artifacts or files)');
14
+ const CONTINUE_FRONTIER = optionalWorkflow('continue', "that is `/opsx:continue`'s job", 'creating them is a separate step, outside this workflow');
15
+ /**
16
+ * `apply` and `archive` are in the `core` profile but not guaranteed in a
17
+ * custom one, so their handoffs are resolved the same way.
18
+ */
19
+ const APPLY_DELTA_HANDOFF = optionalWorkflow('apply', 'suggest `/opsx:apply` to carry the delta into code', 'say that the code may need updating and offer to carry the delta into it');
20
+ const APPLY_GUARDRAIL = optionalWorkflow('apply', 'stop and point to `/opsx:apply`', 'stop and say that the revised plan now implies code changes; implementing them is a separate step');
21
+ const ARCHIVE_HANDOFF = optionalWorkflow('archive', 'suggest `/opsx:archive`', 'suggest archiving with `openspec archive "<name>"`');
22
+ const INTENT_CHANGE_GUARDRAIL = optionalWorkflow('new', 'recommend starting fresh with `/opsx:new` (the "Update vs. Start Fresh" heuristic)', 'ask for a distinct unused change name and recommend `openspec new change "<new-change-name>"` instead (the "Update vs. Start Fresh" heuristic)');
2
23
  export function getUpdateChangeSkillTemplate() {
3
24
  return {
4
25
  name: 'openspec-update-change',
5
- description: "Update an OpenSpec change by revising its existing planning artifacts and keeping them coherent with one another. Use when the user wants to revise a change's plan, fold new decisions into it, or reconcile its artifacts after an edit. Never edits code.",
26
+ description: "Update an OpenSpec change by revising its existing planning artifacts and keeping them coherent with one another. Use when the user wants to revise a change's plan, fold new decisions into it, or reconcile its artifacts after an edit. Also use when the user says \"openspec update change\" or \"opsx update\". If the user means the openspec update CLI command, which refreshes generated files, run that command instead. Never edits code.",
6
27
  instructions: `Revise a change's existing planning artifacts and keep them coherent. Never edit code.
7
28
 
8
29
  ${STORE_SELECTION_GUIDANCE}
9
30
 
31
+ ${PROJECT_ROOT_GUARD}
32
+
10
33
  **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.
11
34
 
12
- \`/opsx:continue\` is an optional workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "<name>" --json\` shows the next artifact and \`openspec instructions "<artifact-id>" --change "<name>" --json\` explains how to create it.
35
+ ${CONTINUE_SCOPE_NOTE}
13
36
 
14
37
  **Steps**
15
38
 
@@ -50,13 +73,14 @@ ${STORE_SELECTION_GUIDANCE}
50
73
 
51
74
  4. **Read and reconcile**
52
75
  - Read the artifact(s) the request touches and the change's other existing artifacts.
53
- - Apply the requested edit. Then check every other existing artifact against it - in ANY direction: an edit to a later artifact may require revising an earlier one, not only the other way around. Build order is a useful reading order, not a constraint on which artifacts may be revised.
76
+ - Draft the requested edit in the conversation, not in files. Work out exactly what it changes; step 5 owns every write. Then check every other existing artifact against the drafted edit - in ANY direction: an edit to a later artifact may require revising an earlier one, not only the other way around. Build order is a useful reading order, not a constraint on which artifacts may be revised.
54
77
  - Note everything that is now inconsistent, missing, or contradictory.
55
- - Revise only files that already exist (\`existingOutputPaths\`). Do NOT create artifacts that don't exist yet, and do NOT invent new files under a glob artifact - note them and point the user to \`/opsx:continue\` to create them.
56
- - If the change is already coherent, say so and make no edits.
78
+ - Propose revisions only to files that already exist (\`existingOutputPaths\`). Do NOT create artifacts that don't exist yet, and do NOT invent new files under a glob artifact - note them and ${CONTINUE_CREATE_THEM}.
79
+ - If the change is already coherent, say so and propose no revisions.
57
80
 
58
81
  5. **Confirm and apply, one artifact at a time**
59
- - Show each proposed revision and why. Write only after the user confirms.
82
+ - This step performs every artifact write in this workflow; no earlier step edits an artifact.
83
+ - Show each proposed revision and why - including the requested edit drafted in step 4. Write only after the user confirms.
60
84
  - If the user rejects a revision, do not write it - leave that artifact unchanged.
61
85
  - When a substantial rewrite is needed, get that artifact's rules and template first:
62
86
  \`\`\`bash
@@ -64,24 +88,24 @@ ${STORE_SELECTION_GUIDANCE}
64
88
  \`\`\`
65
89
 
66
90
  6. **Point to the next step (guidance only - NEVER act on it)**
67
- - Artifacts still missing -> suggest \`/opsx:continue\` to create them.
68
- - Change already implemented (tasks checked off / already applied) -> the code may no longer match the revised plan; suggest \`/opsx:apply\` to carry the delta into code.
69
- - Everything done and implemented -> suggest \`/opsx:archive\`.
91
+ - Artifacts still missing -> ${CONTINUE_NEXT_STEP}.
92
+ - Change already implemented (tasks checked off / already applied) -> the code may no longer match the revised plan; ${APPLY_DELTA_HANDOFF}.
93
+ - Everything done and implemented -> ${ARCHIVE_HANDOFF}.
70
94
 
71
95
  **Output**
72
96
 
73
97
  After each invocation, show:
74
98
  - Which artifacts were revised (and which proposed revisions were rejected)
75
- - Anything deferred to \`/opsx:continue\` (not-yet-created artifacts or files)
99
+ - ${CONTINUE_DEFERRED}
76
100
  - Where the change stands and the recommended next command
77
101
 
78
102
  **Guardrails**
79
- - Planning artifacts only - NEVER edit implementation code. If the revised plan implies code changes, stop and point to \`/opsx:apply\`.
103
+ - Planning artifacts only - NEVER edit implementation code. If the revised plan implies code changes, ${APPLY_GUARDRAIL}.
80
104
  - Use the artifact ids and paths reported by \`openspec status\`; never branch on hardcoded artifact names.
81
105
  - Edit only the concrete files in \`existingOutputPaths\`; never write to a glob \`resolvedOutputPath\`.
82
- - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is \`/opsx:continue\`'s job.
106
+ - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - ${CONTINUE_FRONTIER}.
83
107
  - Confirm every edit with the user before writing.
84
- - If the request changes the change's *intent* rather than refining it, first verify whether the optional \`/opsx:new\` workflow is available. If it is, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). If it is unavailable, ask for a distinct unused change name and recommend \`openspec new change "<new-change-name>"\` instead.`,
108
+ - If the request changes the change's *intent* rather than refining it, ${INTENT_CHANGE_GUARDRAIL}.`,
85
109
  license: 'MIT',
86
110
  compatibility: 'Requires openspec CLI.',
87
111
  metadata: { author: 'openspec', version: '1.0' },
@@ -97,9 +121,11 @@ export function getOpsxUpdateCommandTemplate() {
97
121
 
98
122
  ${STORE_SELECTION_GUIDANCE}
99
123
 
124
+ ${PROJECT_ROOT_GUARD}
125
+
100
126
  **Input**: Optionally specify a change name after \`/opsx:update\` (e.g., \`/opsx:update add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
101
127
 
102
- \`/opsx:continue\` is an optional workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "<name>" --json\` shows the next artifact and \`openspec instructions "<artifact-id>" --change "<name>" --json\` explains how to create it.
128
+ ${CONTINUE_SCOPE_NOTE}
103
129
 
104
130
  **Steps**
105
131
 
@@ -140,13 +166,14 @@ ${STORE_SELECTION_GUIDANCE}
140
166
 
141
167
  4. **Read and reconcile**
142
168
  - Read the artifact(s) the request touches and the change's other existing artifacts.
143
- - Apply the requested edit. Then check every other existing artifact against it - in ANY direction: an edit to a later artifact may require revising an earlier one, not only the other way around. Build order is a useful reading order, not a constraint on which artifacts may be revised.
169
+ - Draft the requested edit in the conversation, not in files. Work out exactly what it changes; step 5 owns every write. Then check every other existing artifact against the drafted edit - in ANY direction: an edit to a later artifact may require revising an earlier one, not only the other way around. Build order is a useful reading order, not a constraint on which artifacts may be revised.
144
170
  - Note everything that is now inconsistent, missing, or contradictory.
145
- - Revise only files that already exist (\`existingOutputPaths\`). Do NOT create artifacts that don't exist yet, and do NOT invent new files under a glob artifact - note them and point the user to \`/opsx:continue\` to create them.
146
- - If the change is already coherent, say so and make no edits.
171
+ - Propose revisions only to files that already exist (\`existingOutputPaths\`). Do NOT create artifacts that don't exist yet, and do NOT invent new files under a glob artifact - note them and ${CONTINUE_CREATE_THEM}.
172
+ - If the change is already coherent, say so and propose no revisions.
147
173
 
148
174
  5. **Confirm and apply, one artifact at a time**
149
- - Show each proposed revision and why. Write only after the user confirms.
175
+ - This step performs every artifact write in this workflow; no earlier step edits an artifact.
176
+ - Show each proposed revision and why - including the requested edit drafted in step 4. Write only after the user confirms.
150
177
  - If the user rejects a revision, do not write it - leave that artifact unchanged.
151
178
  - When a substantial rewrite is needed, get that artifact's rules and template first:
152
179
  \`\`\`bash
@@ -154,24 +181,24 @@ ${STORE_SELECTION_GUIDANCE}
154
181
  \`\`\`
155
182
 
156
183
  6. **Point to the next step (guidance only - NEVER act on it)**
157
- - Artifacts still missing -> suggest \`/opsx:continue\` to create them.
158
- - Change already implemented (tasks checked off / already applied) -> the code may no longer match the revised plan; suggest \`/opsx:apply\` to carry the delta into code.
159
- - Everything done and implemented -> suggest \`/opsx:archive\`.
184
+ - Artifacts still missing -> ${CONTINUE_NEXT_STEP}.
185
+ - Change already implemented (tasks checked off / already applied) -> the code may no longer match the revised plan; ${APPLY_DELTA_HANDOFF}.
186
+ - Everything done and implemented -> ${ARCHIVE_HANDOFF}.
160
187
 
161
188
  **Output**
162
189
 
163
190
  After each invocation, show:
164
191
  - Which artifacts were revised (and which proposed revisions were rejected)
165
- - Anything deferred to \`/opsx:continue\` (not-yet-created artifacts or files)
192
+ - ${CONTINUE_DEFERRED}
166
193
  - Where the change stands and the recommended next command
167
194
 
168
195
  **Guardrails**
169
- - Planning artifacts only - NEVER edit implementation code. If the revised plan implies code changes, stop and point to \`/opsx:apply\`.
196
+ - Planning artifacts only - NEVER edit implementation code. If the revised plan implies code changes, ${APPLY_GUARDRAIL}.
170
197
  - Use the artifact ids and paths reported by \`openspec status\`; never branch on hardcoded artifact names.
171
198
  - Edit only the concrete files in \`existingOutputPaths\`; never write to a glob \`resolvedOutputPath\`.
172
- - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is \`/opsx:continue\`'s job.
199
+ - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - ${CONTINUE_FRONTIER}.
173
200
  - Confirm every edit with the user before writing.
174
- - If the request changes the change's *intent* rather than refining it, first verify whether the optional \`/opsx:new\` workflow is available. If it is, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). If it is unavailable, ask for a distinct unused change name and recommend \`openspec new change "<new-change-name>"\` instead.`
201
+ - If the request changes the change's *intent* rather than refining it, ${INTENT_CHANGE_GUARDRAIL}.`
175
202
  };
176
203
  }
177
204
  //# sourceMappingURL=update-change.js.map