From 421d3cdf890380f16b3f48f61067e790cd0fdf2f Mon Sep 17 00:00:00 2001 From: Clay Good Date: Mon, 3 Aug 2026 15:30:57 -0500 Subject: [PATCH 1/5] fix(templates): correct generated workflow guidance --- .changeset/fix-generated-workflow-guidance.md | 5 + skills/openspec-apply-change/SKILL.md | 2 +- skills/openspec-archive-change/SKILL.md | 2 +- skills/openspec-bulk-archive-change/SKILL.md | 2 +- skills/openspec-continue-change/SKILL.md | 2 +- skills/openspec-explore/SKILL.md | 2 +- skills/openspec-ff-change/SKILL.md | 2 +- skills/openspec-new-change/SKILL.md | 2 +- skills/openspec-onboard/SKILL.md | 2 +- skills/openspec-propose/SKILL.md | 2 +- skills/openspec-sync-specs/SKILL.md | 9 +- skills/openspec-update-change/SKILL.md | 6 +- skills/openspec-verify-change/SKILL.md | 2 +- .../templates/workflows/store-selection.ts | 2 +- src/core/templates/workflows/sync-specs.ts | 14 ++- src/core/templates/workflows/update-change.ts | 8 +- .../templates/skill-templates-parity.test.ts | 100 +++++++++++------- test/core/templates/update-change.test.ts | 18 ++++ 18 files changed, 127 insertions(+), 55 deletions(-) create mode 100644 .changeset/fix-generated-workflow-guidance.md diff --git a/.changeset/fix-generated-workflow-guidance.md b/.changeset/fix-generated-workflow-guidance.md new file mode 100644 index 0000000000..d378442f8c --- /dev/null +++ b/.changeset/fix-generated-workflow-guidance.md @@ -0,0 +1,5 @@ +--- +"@fission-ai/openspec": patch +--- + +Keep generated workflows on the selected store, handle the optional continue workflow, and validate synced specs before reporting success. diff --git a/skills/openspec-apply-change/SKILL.md b/skills/openspec-apply-change/SKILL.md index df53a6bb9c..7382f9dea1 100644 --- a/skills/openspec-apply-change/SKILL.md +++ b/skills/openspec-apply-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Implement tasks from an OpenSpec change. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. diff --git a/skills/openspec-archive-change/SKILL.md b/skills/openspec-archive-change/SKILL.md index fac60b5f37..8d5a1ed208 100644 --- a/skills/openspec-archive-change/SKILL.md +++ b/skills/openspec-archive-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Archive a completed change in the experimental workflow. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. diff --git a/skills/openspec-bulk-archive-change/SKILL.md b/skills/openspec-bulk-archive-change/SKILL.md index 5d7289d812..2ac0590c5a 100644 --- a/skills/openspec-bulk-archive-change/SKILL.md +++ b/skills/openspec-bulk-archive-change/SKILL.md @@ -13,7 +13,7 @@ Archive multiple completed changes in a single operation. This skill allows you to batch-archive changes, handling spec conflicts intelligently by checking the codebase to determine what's actually implemented. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **Input**: None required (prompts for selection) diff --git a/skills/openspec-continue-change/SKILL.md b/skills/openspec-continue-change/SKILL.md index 5faa6a2178..8e74ec35b2 100644 --- a/skills/openspec-continue-change/SKILL.md +++ b/skills/openspec-continue-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Continue working on a change by creating the next artifact. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. diff --git a/skills/openspec-explore/SKILL.md b/skills/openspec-explore/SKILL.md index 74f0a7c089..919c64dea1 100644 --- a/skills/openspec-explore/SKILL.md +++ b/skills/openspec-explore/SKILL.md @@ -15,7 +15,7 @@ Enter explore mode. Think deeply. Visualize freely. Follow the conversation wher **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. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. --- diff --git a/skills/openspec-ff-change/SKILL.md b/skills/openspec-ff-change/SKILL.md index 2edba0652c..90cd54c0cb 100644 --- a/skills/openspec-ff-change/SKILL.md +++ b/skills/openspec-ff-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Fast-forward through artifact creation - generate everything needed to start implementation in one go. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **Input**: The user's request should include a change name (kebab-case) OR a description of what they want to build. diff --git a/skills/openspec-new-change/SKILL.md b/skills/openspec-new-change/SKILL.md index 18b03b9793..e99448cbac 100644 --- a/skills/openspec-new-change/SKILL.md +++ b/skills/openspec-new-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Start a new change using the experimental artifact-driven approach. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **Input**: The user's request should include a change name (kebab-case) OR a description of what they want to build. diff --git a/skills/openspec-onboard/SKILL.md b/skills/openspec-onboard/SKILL.md index b34ad65aeb..33808e2c1f 100644 --- a/skills/openspec-onboard/SKILL.md +++ b/skills/openspec-onboard/SKILL.md @@ -11,7 +11,7 @@ metadata: Guide the user through their first complete OpenSpec workflow cycle. This is a teaching experience—you'll do real work in their codebase while explaining each step. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. --- diff --git a/skills/openspec-propose/SKILL.md b/skills/openspec-propose/SKILL.md index e2b8af831e..b3b4e1f38a 100644 --- a/skills/openspec-propose/SKILL.md +++ b/skills/openspec-propose/SKILL.md @@ -21,7 +21,7 @@ When ready to implement, run /openspec-apply-change --- -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **Input**: The user's request should include a change name (kebab-case) OR a description of what they want to build. diff --git a/skills/openspec-sync-specs/SKILL.md b/skills/openspec-sync-specs/SKILL.md index 4fd5ffd7f4..a8f9fdb87e 100644 --- a/skills/openspec-sync-specs/SKILL.md +++ b/skills/openspec-sync-specs/SKILL.md @@ -13,7 +13,7 @@ Sync delta specs from a change to main specs. 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). -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. @@ -144,7 +144,12 @@ This is an **agent-driven** operation - you will read delta specs and directly e - Add Requirements section with the ADDED requirements - Follow the **Main Spec Format Reference** below -5. **Show summary** +5. **Validate updated main specs** + + Run `openspec validate --specs` with the same selected-root flags used earlier. + If validation fails, report the problems and do not claim the sync succeeded. + +6. **Show summary** After applying all changes, summarize: - Which capabilities were updated diff --git a/skills/openspec-update-change/SKILL.md b/skills/openspec-update-change/SKILL.md index 88986da8ab..c138136b13 100644 --- a/skills/openspec-update-change/SKILL.md +++ b/skills/openspec-update-change/SKILL.md @@ -11,10 +11,12 @@ metadata: Revise a change's existing planning artifacts and keep them coherent. Never edit code. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. +`/openspec-continue-change` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, `openspec status --change "" --json` shows the next artifact and `openspec instructions --change "" --json` explains how to create it. + **Steps** 1. **Select the change** @@ -86,4 +88,4 @@ After each invocation, show: - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is `/openspec-continue-change`'s job. - Confirm every edit with the user before writing. - If the request changes the change's *intent* rather than refining it, recommend starting fresh with `/openspec-new-change` (the "Update vs. Start Fresh" heuristic). -- `/openspec-continue-change` and `/openspec-new-change` may not be installed (core profile). When suggesting one that is unavailable, point to the CLI instead: `openspec status --change "" --json` shows the next artifact and `openspec instructions --change "" --json` explains how to create it. +- `/openspec-new-change` is an expanded-profile workflow and may not be installed. When it is unavailable, recommend starting a fresh change with `openspec new change ` instead. diff --git a/skills/openspec-verify-change/SKILL.md b/skills/openspec-verify-change/SKILL.md index 3779b0a2f6..c64f513226 100644 --- a/skills/openspec-verify-change/SKILL.md +++ b/skills/openspec-verify-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Verify that an implementation matches the change artifacts (specs, tasks, design). -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. diff --git a/src/core/templates/workflows/store-selection.ts b/src/core/templates/workflows/store-selection.ts index 67fe9fec10..e2bff82271 100644 --- a/src/core/templates/workflows/store-selection.ts +++ b/src/core/templates/workflows/store-selection.ts @@ -4,4 +4,4 @@ * Interpolated into every workflow's instructions so generated skills * consistently teach how to target a registered store with `--store `. */ -export const STORE_SELECTION_GUIDANCE = `**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run \`openspec store list --json\` to discover registered store ids, then pass \`--store \` on the commands that read or write specs and changes (\`new change\`, \`status\`, \`instructions\`, \`list\`, \`show\`, \`validate\`, \`archive\`, \`doctor\`, \`context\`, \`view\`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local \`openspec/\` root.`; +export const STORE_SELECTION_GUIDANCE = `**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run \`openspec store list --json\` to discover registered store ids, then pass \`--store \` on the commands that read or write specs and changes (\`new change\`, \`status\`, \`instructions\`, \`list\`, \`show\`, \`validate\`, \`archive\`, \`doctor\`, \`context\`, \`view\`). Once selected, treat \`--store \` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local \`openspec/\` root.`; diff --git a/src/core/templates/workflows/sync-specs.ts b/src/core/templates/workflows/sync-specs.ts index ba742d06ce..092959db45 100644 --- a/src/core/templates/workflows/sync-specs.ts +++ b/src/core/templates/workflows/sync-specs.ts @@ -146,7 +146,12 @@ ${STORE_SELECTION_GUIDANCE} - Add Requirements section with the ADDED requirements - Follow the **Main Spec Format Reference** below -5. **Show summary** +5. **Validate updated main specs** + + Run \`openspec validate --specs\` with the same selected-root flags used earlier. + If validation fails, report the problems and do not claim the sync succeeded. + +6. **Show summary** After applying all changes, summarize: - Which capabilities were updated @@ -399,7 +404,12 @@ ${STORE_SELECTION_GUIDANCE} - Add Requirements section with the ADDED requirements - Follow the **Main Spec Format Reference** below -5. **Show summary** +5. **Validate updated main specs** + + Run \`openspec validate --specs\` with the same selected-root flags used earlier. + If validation fails, report the problems and do not claim the sync succeeded. + +6. **Show summary** After applying all changes, summarize: - Which capabilities were updated diff --git a/src/core/templates/workflows/update-change.ts b/src/core/templates/workflows/update-change.ts index 3e8549b677..3efdc0ceeb 100644 --- a/src/core/templates/workflows/update-change.ts +++ b/src/core/templates/workflows/update-change.ts @@ -17,6 +17,8 @@ ${STORE_SELECTION_GUIDANCE} **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. +\`/opsx:continue\` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "" --json\` shows the next artifact and \`openspec instructions --change "" --json\` explains how to create it. + **Steps** 1. **Select the change** @@ -88,7 +90,7 @@ After each invocation, show: - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is \`/opsx:continue\`'s job. - Confirm every edit with the user before writing. - If the request changes the change's *intent* rather than refining it, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). -- \`/opsx:continue\` and \`/opsx:new\` may not be installed (core profile). When suggesting one that is unavailable, point to the CLI instead: \`openspec status --change "" --json\` shows the next artifact and \`openspec instructions --change "" --json\` explains how to create it.`, +- \`/opsx:new\` is an expanded-profile workflow and may not be installed. When it is unavailable, recommend starting a fresh change with \`openspec new change \` instead.`, license: 'MIT', compatibility: 'Requires openspec CLI.', metadata: { author: 'openspec', version: '1.0' }, @@ -107,6 +109,8 @@ ${STORE_SELECTION_GUIDANCE} **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. +\`/opsx:continue\` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "" --json\` shows the next artifact and \`openspec instructions --change "" --json\` explains how to create it. + **Steps** 1. **Select the change** @@ -178,6 +182,6 @@ After each invocation, show: - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is \`/opsx:continue\`'s job. - Confirm every edit with the user before writing. - If the request changes the change's *intent* rather than refining it, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). -- \`/opsx:continue\` and \`/opsx:new\` may not be installed (core profile). When suggesting one that is unavailable, point to the CLI instead: \`openspec status --change "" --json\` shows the next artifact and \`openspec instructions --change "" --json\` explains how to create it.` +- \`/opsx:new\` is an expanded-profile workflow and may not be installed. When it is unavailable, recommend starting a fresh change with \`openspec new change \` instead.` }; } diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index a9aea3d822..ccf05be0a0 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -37,46 +37,46 @@ import { import { STORE_SELECTION_GUIDANCE } from '../../../src/core/templates/workflows/store-selection.js'; const EXPECTED_FUNCTION_HASHES: Record = { - getExploreSkillTemplate: '1ed2dfea7d1f020ba4515d1814f2a139fd070a9c0a7c08a726e49bd65a033930', - getNewChangeSkillTemplate: 'd2b4be99614c57ae5b7d48e477d462729fafb063b0a7418d73372ff35eee6cfc', - getContinueChangeSkillTemplate: '676e7472977d2b6f4d922ce384db1f15020c195f94d6cd4ee71abcf0201e28a9', - getApplyChangeSkillTemplate: '031cf8f8ffc2937fc4051651bd5e1fc6159bfd225605d8e4c3181054a4e52b38', - getFfChangeSkillTemplate: '225a8eaf1b3769ac5d43e079297c5fa9cc20fc2e34fec9bb0d887c8c1fb0ea71', - getSyncSpecsSkillTemplate: '904469b74b53021ca43f73f2b64a83080015707f49d7e6d913e2e1adb35ccb9f', - getOnboardSkillTemplate: '856b5f451f45093f8906967da29b4e0479c7c271e401eab2ef58165800a67284', - getOpsxExploreCommandTemplate: 'e9674ddace813e685b0e9fe37149140a3d33d48aa20b9ba2b0963a7c49c9aea7', - getOpsxNewCommandTemplate: '652adc870f16bb260d54436356132b6ee051a9ed7cc0464603fb31f4db259762', - getOpsxContinueCommandTemplate: 'bcf0ad1c55b71346147c5b4dbaed016c77c9718f960012d8efc9d3d2089d0e00', - getOpsxApplyCommandTemplate: '18c82fc48e65084065171e44f811db8fdc96bd6cb0f61fe8f31324207f4861c7', - getOpsxFfCommandTemplate: '678375642a21d255444f0ba717e659abb2cc2b7474981d52eae900a0793e3e4d', - getArchiveChangeSkillTemplate: 'ee27b4c15a2f13bbb0ab0ceb5f4b10fa5e19dd70128ca58dd3f482c1f2a8f97f', - getBulkArchiveChangeSkillTemplate: 'e67a6fae6553e01c9930bd08f11465a205637fec6c72726b0cfa1a735920bba4', - getOpsxSyncCommandTemplate: '40c7ff54221918dc6cae8a4d376a6e8897a6926721a337fb1f037f0000861d54', - getVerifyChangeSkillTemplate: '917de96cc8341799107b0617979cdaf30e121c51676272f5caef143b090583f9', - getOpsxArchiveCommandTemplate: '729fcdc9be6af7abb65f4ed3400ce6e95eef256d3660cfaeac3ef07e89144671', - getOpsxOnboardCommandTemplate: '3fda1bb6ce52cdb240d1ade84319ea44160aef79573052ce58b77eb662de98a1', - getOpsxBulkArchiveCommandTemplate: '87a003ac49d0303a5b77dc935bcff1d830ca5434b129ba788d5d44253f814f87', - getOpsxVerifyCommandTemplate: '29e3913c93566e689971d8c15c3348ba4169ebf6b1d403f5ac9974605c734baa', - getOpsxProposeSkillTemplate: '06a8f7d272db8d3cb113dc05d606630d1e5aedd267c2722e971d1175e0d8bb40', - getOpsxProposeCommandTemplate: 'ed3ad596d9bb238830b4fcbe566e3c1ba9d0db62f4a92cdb28c38262dc3f04df', + getExploreSkillTemplate: '87ab8ad0914cdcb83332e0fa8bae4cfc887c2e21ad1acd1dbc1cde5c866912fe', + getNewChangeSkillTemplate: 'ede5485cb70e079039e16a410343389a3b6940df244a7cb8828b6aa478d16222', + getContinueChangeSkillTemplate: '98819c8e96053c330aa97929507aaec6070c517459cf21d81608cb320d6eee88', + getApplyChangeSkillTemplate: '38fac7eb01ac8113aebcb5421256a6ec5dd939c432d8062643f4e8ddcf66c019', + getFfChangeSkillTemplate: 'b29e80fe10c2d8393a6d01cf40eb1f684e18d2a5790c9bec3a890513abe72807', + getSyncSpecsSkillTemplate: 'df71a66661ea98a41cceacc40a12f2230c0bec7ee31a2408d2cfe4942c803a4d', + getOnboardSkillTemplate: '256acdc3f3321f0665df3a02cff7ee35782fa2242e9b05696684918f6be48428', + getOpsxExploreCommandTemplate: 'cd2ada418f8a3a972d7ba3030973a2e23a89de28ec8847454099c316b7d5b40b', + getOpsxNewCommandTemplate: '0955d26857221dae627530aeec3ce499b2ca898fe02232492c130c32d3e8a3d9', + getOpsxContinueCommandTemplate: '75b4407a0854a50be7bffe89348981d50146c438d2c31c06bd0c3d5ae21683d1', + getOpsxApplyCommandTemplate: 'd5d555e28e473b8601b283d220498f4fb51008f2831905f4da8a9fa7c2a9c1ea', + getOpsxFfCommandTemplate: 'a923f13c8e2219e69f6cd4214b2ea1733f4a539b0f0a142c5ec290d248aa1d24', + getArchiveChangeSkillTemplate: '99c4586fe8c9ea41f247a515faef19a2ca14621183f33805924c93012282e8c8', + getBulkArchiveChangeSkillTemplate: '3c7ab3ab67de25089071075fd4ae2095297aefd82a4785481a9c7dd4bb20c007', + getOpsxSyncCommandTemplate: '9f71518e562e8b6e171a4e24894d9bdd9650a7afb3c1a24807596f30245f48b8', + getVerifyChangeSkillTemplate: '65fc5b3f03921f4a645f0826b5637ccf4d6bd077ba27f3f510575cda739dff18', + getOpsxArchiveCommandTemplate: '8f25c5b87ddb246b6c6600486ecf195acfed30de653fe0a0f9e3d89136c66daf', + getOpsxOnboardCommandTemplate: '2626899ad0d459b71fe08565cbd60852ab4e2dccb001ecb1411bc7e45db0b4b9', + getOpsxBulkArchiveCommandTemplate: 'e76857b0ab1270c2730b45a3e10e9c392517fffa85061aebeade5067e7dd9d02', + getOpsxVerifyCommandTemplate: '5ed5c0707d25653205af13bd75c82bfcf8e4be48f29be6d0f10cf7c90a152bdb', + getOpsxProposeSkillTemplate: '1f4efb1439c6c0514088c09a1f5d43107bc209e888b197d3df6ae31a24044355', + getOpsxProposeCommandTemplate: 'b205fef794d5012b68b58b18af80f70fa9f3dde890f554aa1c8995bf2de6b74b', getFeedbackSkillTemplate: 'd7d83c5f7fc2b92fe8f4588a5bf2d9cb315e4c73ec19bcd5ef28270906319a0d', - getUpdateChangeSkillTemplate: 'da1f76a91ba606df6aa895431c79e64ca91580fa952807230e653bddeb2a3c15', - getOpsxUpdateCommandTemplate: 'afbf85f79177a0125bbc2028ed50e23f59ea96c2b6ef4153ed9bce6465c6414e', + getUpdateChangeSkillTemplate: 'c0c22d3f9893f0caadf8303558109208cf4d59676464d5061181768ae719bafe', + getOpsxUpdateCommandTemplate: 'e3953ce7128d4f9a47a5815b67c17221ea170a0ac38a9898b1a5a6faa13bbfce', }; const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { - 'openspec-explore': '67eeacf1c797eebbc20926555c1a29cbc06fdd12aae5b8f06acf3d0445e1a51a', - 'openspec-new-change': 'b56c7f8dd85b462c9fea5c36eeaadff9b231b41e21dde12f156fb261959aa82a', - 'openspec-continue-change': '2e1a7d17ec021949d115c72227729609bf9980ad1f23445af117c09834711121', - 'openspec-apply-change': '49fc5772404e3033085384ee214c44488c93880a596a9a05dcad42f9ce86cf83', - 'openspec-ff-change': '4228d75e3571097164f2360e2ad3063a5b88d44750078c3601b23a89e74c1de6', - 'openspec-sync-specs': '668a2044cb1688969279357c04034ba6ef6c2d38123cc3f6ae9b5e7761baac04', - 'openspec-archive-change': '7fde55c06ae896b5f628b00e0dddceb9f86fdbf431e3f4dcd5fc0aacac16d808', - 'openspec-bulk-archive-change': '789d60d5874eab9714aef6a0b1109af0af2f9f23f57767b4641db89849dd0fce', - 'openspec-verify-change': '1c3f73a36be691a18d3acb200d22e6874004d6d4a5d3e2e346ae95a7379e9da8', - 'openspec-onboard': '6eb124af3a9f35efe601ff373406fad93447a1375e0bb4e27a35b0c3fd476851', - 'openspec-propose': '6b49634d3672e7fef4750a8c7572a661fec0dafe6d52a0075b41a2c87a793871', - 'openspec-update-change': '1e61edfcd229b5b3e7ea957a5606712805cae19709304b26448fe111657a7255', + 'openspec-explore': 'b0abaad3c38653788d0463d5da6b90f9dab0433f420e1b78a6eebcf052a8ebd1', + 'openspec-new-change': '37150481c16edff989ea841257451dc0c22f4b16763794f2686983c32f1d66bd', + 'openspec-continue-change': '7c57f6303ba6b36b81119aaf7e515bd21f2864d90f9bd9586d453aa034d7d685', + 'openspec-apply-change': '5190dcbc86c1e8fc3bfc7b94ff023f0543ba435194c17f26d502621dd25f1820', + 'openspec-ff-change': 'f394c841ef796326382f113a7ca9003304b8c7189a8fb88d29981316987e1591', + 'openspec-sync-specs': '00d30e7fca274eb4faaeb23a75078fe51ede6e6329954f166baa9af011c177c4', + 'openspec-archive-change': '0654368ecec95ea37aa6e93441b7378a97b96cafe38a05304c0bb4f8120a81d4', + 'openspec-bulk-archive-change': 'd1331aec02d220cf36ca257b804cb4643ada0c0e68e3d593f01b993f88372bbd', + 'openspec-verify-change': 'c2d6d595cefde562696cd103137d76c80b3d13f6cb42c60d0c236523abdecbb3', + 'openspec-onboard': '384fd2ec91b4da7fa726f4dfd3f316b13277de02ac003417a428f1a12e400511', + 'openspec-propose': 'a54d3635ae1756be4733ae1bfe45984eaab253160f2d93d4be37a9c431b5662a', + 'openspec-update-change': '3f8e3f561d4231e372f918eb2ae7ae06c7a6896195d1a6701c80baa2538342f1', }; // Intentionally excludes getFeedbackSkillTemplate: this list only models templates @@ -204,6 +204,34 @@ describe('skill templates split parity', () => { expect(getFeedbackSkillTemplate().instructions).not.toContain('**Store selection:**'); }); + it('keeps a selected store on every applicable workflow command', () => { + expect(STORE_SELECTION_GUIDANCE).toContain( + 'treat `--store ` as sticky for the rest of the workflow' + ); + expect(STORE_SELECTION_GUIDANCE).toContain( + 'append it to every applicable command below, even when the example does not repeat the flag' + ); + }); + + it('validates synced main specs before reporting success', () => { + const variants: Array<[string, string]> = [ + ['sync skill', getSyncSpecsSkillTemplate().instructions], + ['sync command', getOpsxSyncCommandTemplate().content], + ]; + + for (const [variant, content] of variants) { + const validation = content.indexOf('openspec validate --specs'); + const summary = content.indexOf('**Show summary**'); + + expect(validation, variant).toBeGreaterThanOrEqual(0); + expect(summary, variant).toBeGreaterThan(validation); + expect(content, variant).toContain('same selected-root flags'); + expect(content, variant).toContain( + 'If validation fails, report the problems and do not claim the sync succeeded' + ); + } + }); + it('generates no workspace-planning residue in any workflow template (4.1)', () => { const allSkills: Array<[string, () => SkillTemplate]> = [ ['openspec-apply-change', getApplyChangeSkillTemplate], diff --git a/test/core/templates/update-change.test.ts b/test/core/templates/update-change.test.ts index d0f5202c52..59641cd75d 100644 --- a/test/core/templates/update-change.test.ts +++ b/test/core/templates/update-change.test.ts @@ -77,6 +77,24 @@ describe('update-change templates', () => { } }); + it('explains the optional continue workflow before suggesting it', () => { + for (const [label, body] of bodies) { + const availabilityGuidance = body.indexOf( + '`/opsx:continue` is an expanded-profile workflow and may not be installed' + ); + const firstSuggestion = body.indexOf('point the user to `/opsx:continue`'); + + expect(availabilityGuidance, label).toBeGreaterThanOrEqual(0); + expect(firstSuggestion, label).toBeGreaterThan(availabilityGuidance); + expect(body, label).toContain( + 'If it is unavailable, `openspec status --change "" --json` shows the next artifact' + ); + expect(body, label).toContain( + '`openspec instructions --change "" --json` explains how to create it' + ); + } + }); + it('confirms every edit and redirects intent changes to /opsx:new', () => { for (const [label, body] of bodies) { expect(body, label).toContain('Write only after the user confirms'); From 2e3460d1b23be71178c9fd812feaea160e100609 Mon Sep 17 00:00:00 2001 From: Clay Good Date: Mon, 3 Aug 2026 15:47:56 -0500 Subject: [PATCH 2/5] fix(templates): address workflow review feedback --- skills/openspec-update-change/SKILL.md | 5 ++--- src/core/templates/workflows/update-change.ts | 10 ++++------ test/core/templates/skill-templates-parity.test.ts | 6 +++--- test/core/templates/update-change.test.ts | 12 ++++++++++-- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/skills/openspec-update-change/SKILL.md b/skills/openspec-update-change/SKILL.md index c138136b13..759bee07ec 100644 --- a/skills/openspec-update-change/SKILL.md +++ b/skills/openspec-update-change/SKILL.md @@ -15,7 +15,7 @@ Revise a change's existing planning artifacts and keep them coherent. Never edit **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. -`/openspec-continue-change` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, `openspec status --change "" --json` shows the next artifact and `openspec instructions --change "" --json` explains how to create it. +`/openspec-continue-change` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, `openspec status --change "" --json` shows the next artifact and `openspec instructions "" --change "" --json` explains how to create it. **Steps** @@ -87,5 +87,4 @@ After each invocation, show: - Edit only the concrete files in `existingOutputPaths`; never write to a glob `resolvedOutputPath`. - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is `/openspec-continue-change`'s job. - Confirm every edit with the user before writing. -- If the request changes the change's *intent* rather than refining it, recommend starting fresh with `/openspec-new-change` (the "Update vs. Start Fresh" heuristic). -- `/openspec-new-change` is an expanded-profile workflow and may not be installed. When it is unavailable, recommend starting a fresh change with `openspec new change ` instead. +- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile `/openspec-new-change` workflow is available. If it is, recommend starting fresh with `/openspec-new-change` (the "Update vs. Start Fresh" heuristic). If it is unavailable, recommend starting a fresh change with `openspec new change ""` instead. diff --git a/src/core/templates/workflows/update-change.ts b/src/core/templates/workflows/update-change.ts index 3efdc0ceeb..ef8f20fc78 100644 --- a/src/core/templates/workflows/update-change.ts +++ b/src/core/templates/workflows/update-change.ts @@ -17,7 +17,7 @@ ${STORE_SELECTION_GUIDANCE} **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. -\`/opsx:continue\` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "" --json\` shows the next artifact and \`openspec instructions --change "" --json\` explains how to create it. +\`/opsx:continue\` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "" --json\` shows the next artifact and \`openspec instructions "" --change "" --json\` explains how to create it. **Steps** @@ -89,8 +89,7 @@ After each invocation, show: - Edit only the concrete files in \`existingOutputPaths\`; never write to a glob \`resolvedOutputPath\`. - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is \`/opsx:continue\`'s job. - Confirm every edit with the user before writing. -- If the request changes the change's *intent* rather than refining it, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). -- \`/opsx:new\` is an expanded-profile workflow and may not be installed. When it is unavailable, recommend starting a fresh change with \`openspec new change \` instead.`, +- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile \`/opsx:new\` workflow is available. If it is, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). If it is unavailable, recommend starting a fresh change with \`openspec new change ""\` instead.`, license: 'MIT', compatibility: 'Requires openspec CLI.', metadata: { author: 'openspec', version: '1.0' }, @@ -109,7 +108,7 @@ ${STORE_SELECTION_GUIDANCE} **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. -\`/opsx:continue\` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "" --json\` shows the next artifact and \`openspec instructions --change "" --json\` explains how to create it. +\`/opsx:continue\` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "" --json\` shows the next artifact and \`openspec instructions "" --change "" --json\` explains how to create it. **Steps** @@ -181,7 +180,6 @@ After each invocation, show: - Edit only the concrete files in \`existingOutputPaths\`; never write to a glob \`resolvedOutputPath\`. - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is \`/opsx:continue\`'s job. - Confirm every edit with the user before writing. -- If the request changes the change's *intent* rather than refining it, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). -- \`/opsx:new\` is an expanded-profile workflow and may not be installed. When it is unavailable, recommend starting a fresh change with \`openspec new change \` instead.` +- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile \`/opsx:new\` workflow is available. If it is, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). If it is unavailable, recommend starting a fresh change with \`openspec new change ""\` instead.` }; } diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index ccf05be0a0..e9e2aee09a 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -60,8 +60,8 @@ const EXPECTED_FUNCTION_HASHES: Record = { getOpsxProposeSkillTemplate: '1f4efb1439c6c0514088c09a1f5d43107bc209e888b197d3df6ae31a24044355', getOpsxProposeCommandTemplate: 'b205fef794d5012b68b58b18af80f70fa9f3dde890f554aa1c8995bf2de6b74b', getFeedbackSkillTemplate: 'd7d83c5f7fc2b92fe8f4588a5bf2d9cb315e4c73ec19bcd5ef28270906319a0d', - getUpdateChangeSkillTemplate: 'c0c22d3f9893f0caadf8303558109208cf4d59676464d5061181768ae719bafe', - getOpsxUpdateCommandTemplate: 'e3953ce7128d4f9a47a5815b67c17221ea170a0ac38a9898b1a5a6faa13bbfce', + getUpdateChangeSkillTemplate: '7ed22589fe4f655461d7b9d0fc5202414e75707184bcac5e42cee19dee559f8a', + getOpsxUpdateCommandTemplate: 'f5e47e21440dad17660983da17d3b933adfc5d08f1c049f2451f3de4c7b6136d', }; const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { @@ -76,7 +76,7 @@ const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { 'openspec-verify-change': 'c2d6d595cefde562696cd103137d76c80b3d13f6cb42c60d0c236523abdecbb3', 'openspec-onboard': '384fd2ec91b4da7fa726f4dfd3f316b13277de02ac003417a428f1a12e400511', 'openspec-propose': 'a54d3635ae1756be4733ae1bfe45984eaab253160f2d93d4be37a9c431b5662a', - 'openspec-update-change': '3f8e3f561d4231e372f918eb2ae7ae06c7a6896195d1a6701c80baa2538342f1', + 'openspec-update-change': '6394f32b4ac952f3713a35f56b721c05773a53d1a7dc710dc812814090f11166', }; // Intentionally excludes getFeedbackSkillTemplate: this list only models templates diff --git a/test/core/templates/update-change.test.ts b/test/core/templates/update-change.test.ts index 59641cd75d..ef142c213e 100644 --- a/test/core/templates/update-change.test.ts +++ b/test/core/templates/update-change.test.ts @@ -33,7 +33,7 @@ describe('update-change templates', () => { expect(body, label).toContain(STORE_SELECTION_GUIDANCE); expect(body, label).toContain('openspec list --json'); expect(body, label).toContain('openspec status --change "" --json'); - expect(body, label).toContain('openspec instructions --change "" --json'); + expect(body, label).toContain('openspec instructions "" --change "" --json'); } }); @@ -90,7 +90,7 @@ describe('update-change templates', () => { 'If it is unavailable, `openspec status --change "" --json` shows the next artifact' ); expect(body, label).toContain( - '`openspec instructions --change "" --json` explains how to create it' + '`openspec instructions "" --change "" --json` explains how to create it' ); } }); @@ -101,6 +101,14 @@ describe('update-change templates', () => { expect(body, label).toContain('If the user rejects a revision, do not write it'); expect(body, label).toContain('recommend starting fresh with `/opsx:new`'); expect(body, label).toContain('Update vs. Start Fresh'); + expect(body, label).toContain('openspec new change ""'); + + const newAvailabilityCheck = body.indexOf( + 'first verify whether the expanded-profile `/opsx:new` workflow is available' + ); + const newRecommendation = body.indexOf('recommend starting fresh with `/opsx:new`'); + expect(newAvailabilityCheck, label).toBeGreaterThanOrEqual(0); + expect(newRecommendation, label).toBeGreaterThan(newAvailabilityCheck); } }); }); From 7fbe1ac6ff16e83b600c35feac64f3a44116501a Mon Sep 17 00:00:00 2001 From: Clay Good Date: Mon, 3 Aug 2026 15:54:22 -0500 Subject: [PATCH 3/5] test(templates): pin store-aware commands --- test/core/templates/skill-templates-parity.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index e9e2aee09a..267a89b597 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -211,6 +211,7 @@ describe('skill templates split parity', () => { expect(STORE_SELECTION_GUIDANCE).toContain( 'append it to every applicable command below, even when the example does not repeat the flag' ); + expect(STORE_SELECTION_GUIDANCE).toContain('`context`, `view`'); }); it('validates synced main specs before reporting success', () => { From 3150c34b9e2996dedbdd15cae4f259e717145a0c Mon Sep 17 00:00:00 2001 From: Clay Good Date: Mon, 3 Aug 2026 16:09:26 -0500 Subject: [PATCH 4/5] fix(templates): harden generated workflow guidance --- .changeset/fix-generated-workflow-guidance.md | 2 +- skills/openspec-apply-change/SKILL.md | 2 +- skills/openspec-archive-change/SKILL.md | 2 +- skills/openspec-bulk-archive-change/SKILL.md | 2 +- skills/openspec-continue-change/SKILL.md | 2 +- skills/openspec-explore/SKILL.md | 2 +- skills/openspec-ff-change/SKILL.md | 2 +- skills/openspec-new-change/SKILL.md | 2 +- skills/openspec-onboard/SKILL.md | 2 +- skills/openspec-propose/SKILL.md | 2 +- skills/openspec-sync-specs/SKILL.md | 2 +- skills/openspec-update-change/SKILL.md | 6 +- skills/openspec-verify-change/SKILL.md | 2 +- .../templates/workflows/store-selection.ts | 2 +- src/core/templates/workflows/update-change.ts | 8 +- test/core/init.test.ts | 94 +++++++++++++++++++ .../templates/skill-templates-parity.test.ts | 83 ++++++++-------- test/core/templates/update-change.test.ts | 11 ++- 18 files changed, 168 insertions(+), 60 deletions(-) diff --git a/.changeset/fix-generated-workflow-guidance.md b/.changeset/fix-generated-workflow-guidance.md index d378442f8c..2573500401 100644 --- a/.changeset/fix-generated-workflow-guidance.md +++ b/.changeset/fix-generated-workflow-guidance.md @@ -2,4 +2,4 @@ "@fission-ai/openspec": patch --- -Keep generated workflows on the selected store, handle the optional continue workflow, and validate synced specs before reporting success. +Keep generated workflows on the selected store, handle optional workflow fallbacks safely, and validate synced specs before reporting success. diff --git a/skills/openspec-apply-change/SKILL.md b/skills/openspec-apply-change/SKILL.md index 7382f9dea1..4643e00abf 100644 --- a/skills/openspec-apply-change/SKILL.md +++ b/skills/openspec-apply-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Implement tasks from an OpenSpec change. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. diff --git a/skills/openspec-archive-change/SKILL.md b/skills/openspec-archive-change/SKILL.md index 8d5a1ed208..41cf89e93a 100644 --- a/skills/openspec-archive-change/SKILL.md +++ b/skills/openspec-archive-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Archive a completed change in the experimental workflow. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. diff --git a/skills/openspec-bulk-archive-change/SKILL.md b/skills/openspec-bulk-archive-change/SKILL.md index 2ac0590c5a..b0df1f7e9f 100644 --- a/skills/openspec-bulk-archive-change/SKILL.md +++ b/skills/openspec-bulk-archive-change/SKILL.md @@ -13,7 +13,7 @@ Archive multiple completed changes in a single operation. This skill allows you to batch-archive changes, handling spec conflicts intelligently by checking the codebase to determine what's actually implemented. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **Input**: None required (prompts for selection) diff --git a/skills/openspec-continue-change/SKILL.md b/skills/openspec-continue-change/SKILL.md index 8e74ec35b2..2f4650bd02 100644 --- a/skills/openspec-continue-change/SKILL.md +++ b/skills/openspec-continue-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Continue working on a change by creating the next artifact. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. diff --git a/skills/openspec-explore/SKILL.md b/skills/openspec-explore/SKILL.md index 919c64dea1..7bf71157cf 100644 --- a/skills/openspec-explore/SKILL.md +++ b/skills/openspec-explore/SKILL.md @@ -15,7 +15,7 @@ Enter explore mode. Think deeply. Visualize freely. Follow the conversation wher **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. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. --- diff --git a/skills/openspec-ff-change/SKILL.md b/skills/openspec-ff-change/SKILL.md index 90cd54c0cb..e88c416a16 100644 --- a/skills/openspec-ff-change/SKILL.md +++ b/skills/openspec-ff-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Fast-forward through artifact creation - generate everything needed to start implementation in one go. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **Input**: The user's request should include a change name (kebab-case) OR a description of what they want to build. diff --git a/skills/openspec-new-change/SKILL.md b/skills/openspec-new-change/SKILL.md index e99448cbac..a103bb0748 100644 --- a/skills/openspec-new-change/SKILL.md +++ b/skills/openspec-new-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Start a new change using the experimental artifact-driven approach. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **Input**: The user's request should include a change name (kebab-case) OR a description of what they want to build. diff --git a/skills/openspec-onboard/SKILL.md b/skills/openspec-onboard/SKILL.md index 33808e2c1f..a6e6fd26c9 100644 --- a/skills/openspec-onboard/SKILL.md +++ b/skills/openspec-onboard/SKILL.md @@ -11,7 +11,7 @@ metadata: Guide the user through their first complete OpenSpec workflow cycle. This is a teaching experience—you'll do real work in their codebase while explaining each step. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. --- diff --git a/skills/openspec-propose/SKILL.md b/skills/openspec-propose/SKILL.md index b3b4e1f38a..327d3f65d5 100644 --- a/skills/openspec-propose/SKILL.md +++ b/skills/openspec-propose/SKILL.md @@ -21,7 +21,7 @@ When ready to implement, run /openspec-apply-change --- -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **Input**: The user's request should include a change name (kebab-case) OR a description of what they want to build. diff --git a/skills/openspec-sync-specs/SKILL.md b/skills/openspec-sync-specs/SKILL.md index a8f9fdb87e..c3289ed5cb 100644 --- a/skills/openspec-sync-specs/SKILL.md +++ b/skills/openspec-sync-specs/SKILL.md @@ -13,7 +13,7 @@ Sync delta specs from a change to main specs. 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). -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. diff --git a/skills/openspec-update-change/SKILL.md b/skills/openspec-update-change/SKILL.md index 759bee07ec..084baa0062 100644 --- a/skills/openspec-update-change/SKILL.md +++ b/skills/openspec-update-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Revise a change's existing planning artifacts and keep them coherent. Never edit code. -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. @@ -66,7 +66,7 @@ Revise a change's existing planning artifacts and keep them coherent. Never edit - If the user rejects a revision, do not write it - leave that artifact unchanged. - When a substantial rewrite is needed, get that artifact's rules and template first: ```bash - openspec instructions --change "" --json + openspec instructions "" --change "" --json ``` 6. **Point to the next step (guidance only - NEVER act on it)** @@ -87,4 +87,4 @@ After each invocation, show: - Edit only the concrete files in `existingOutputPaths`; never write to a glob `resolvedOutputPath`. - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is `/openspec-continue-change`'s job. - Confirm every edit with the user before writing. -- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile `/openspec-new-change` workflow is available. If it is, recommend starting fresh with `/openspec-new-change` (the "Update vs. Start Fresh" heuristic). If it is unavailable, recommend starting a fresh change with `openspec new change ""` instead. +- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile `/openspec-new-change` workflow is available. If it is, recommend starting fresh with `/openspec-new-change` (the "Update vs. Start Fresh" heuristic). If it is unavailable, ask for a distinct unused change name and recommend `openspec new change ""` instead. diff --git a/skills/openspec-verify-change/SKILL.md b/skills/openspec-verify-change/SKILL.md index c64f513226..8e62355d05 100644 --- a/skills/openspec-verify-change/SKILL.md +++ b/skills/openspec-verify-change/SKILL.md @@ -11,7 +11,7 @@ metadata: Verify that an implementation matches the change artifacts (specs, tasks, design). -**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `view`). Once selected, treat `--store ` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "" --json --store ""`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. **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. diff --git a/src/core/templates/workflows/store-selection.ts b/src/core/templates/workflows/store-selection.ts index e2bff82271..586ca156d9 100644 --- a/src/core/templates/workflows/store-selection.ts +++ b/src/core/templates/workflows/store-selection.ts @@ -4,4 +4,4 @@ * Interpolated into every workflow's instructions so generated skills * consistently teach how to target a registered store with `--store `. */ -export const STORE_SELECTION_GUIDANCE = `**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run \`openspec store list --json\` to discover registered store ids, then pass \`--store \` on the commands that read or write specs and changes (\`new change\`, \`status\`, \`instructions\`, \`list\`, \`show\`, \`validate\`, \`archive\`, \`doctor\`, \`context\`, \`view\`). Once selected, treat \`--store \` as sticky for the rest of the workflow: append it to every applicable command below, even when the example does not repeat the flag. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local \`openspec/\` root.`; +export const STORE_SELECTION_GUIDANCE = `**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run \`openspec store list --json\` to discover registered store ids, then pass \`--store \` on the commands that read or write specs and changes (\`new change\`, \`status\`, \`instructions\`, \`list\`, \`show\`, \`validate\`, \`archive\`, \`doctor\`, \`context\`, \`view\`). Once selected, treat \`--store \` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run \`openspec status --change "" --json --store ""\`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local \`openspec/\` root.`; diff --git a/src/core/templates/workflows/update-change.ts b/src/core/templates/workflows/update-change.ts index ef8f20fc78..aea08ab676 100644 --- a/src/core/templates/workflows/update-change.ts +++ b/src/core/templates/workflows/update-change.ts @@ -68,7 +68,7 @@ ${STORE_SELECTION_GUIDANCE} - If the user rejects a revision, do not write it - leave that artifact unchanged. - When a substantial rewrite is needed, get that artifact's rules and template first: \`\`\`bash - openspec instructions --change "" --json + openspec instructions "" --change "" --json \`\`\` 6. **Point to the next step (guidance only - NEVER act on it)** @@ -89,7 +89,7 @@ After each invocation, show: - Edit only the concrete files in \`existingOutputPaths\`; never write to a glob \`resolvedOutputPath\`. - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is \`/opsx:continue\`'s job. - Confirm every edit with the user before writing. -- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile \`/opsx:new\` workflow is available. If it is, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). If it is unavailable, recommend starting a fresh change with \`openspec new change ""\` instead.`, +- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile \`/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 ""\` instead.`, license: 'MIT', compatibility: 'Requires openspec CLI.', metadata: { author: 'openspec', version: '1.0' }, @@ -159,7 +159,7 @@ ${STORE_SELECTION_GUIDANCE} - If the user rejects a revision, do not write it - leave that artifact unchanged. - When a substantial rewrite is needed, get that artifact's rules and template first: \`\`\`bash - openspec instructions --change "" --json + openspec instructions "" --change "" --json \`\`\` 6. **Point to the next step (guidance only - NEVER act on it)** @@ -180,6 +180,6 @@ After each invocation, show: - Edit only the concrete files in \`existingOutputPaths\`; never write to a glob \`resolvedOutputPath\`. - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is \`/opsx:continue\`'s job. - Confirm every edit with the user before writing. -- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile \`/opsx:new\` workflow is available. If it is, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). If it is unavailable, recommend starting a fresh change with \`openspec new change ""\` instead.` +- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile \`/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 ""\` instead.` }; } diff --git a/test/core/init.test.ts b/test/core/init.test.ts index 5788493074..a9dc5597f4 100644 --- a/test/core/init.test.ts +++ b/test/core/init.test.ts @@ -195,6 +195,100 @@ describe('InitCommand', () => { expect((await fs.lstat(skillFile)).isSymbolicLink()).toBe(true); }); + it('should generate safe Claude workflow guidance (#1493)', async () => { + const initCommand = new InitCommand({ tools: 'claude', force: true }); + + await initCommand.execute(testDir); + + const generatedFiles = [ + ...[ + 'openspec-propose', + 'openspec-explore', + 'openspec-apply-change', + 'openspec-update-change', + 'openspec-sync-specs', + 'openspec-archive-change', + ].map((name) => path.join(testDir, '.claude', 'skills', name, 'SKILL.md')), + ...['propose', 'explore', 'apply', 'update', 'sync', 'archive'].map((name) => + path.join(testDir, '.claude', 'commands', 'opsx', `${name}.md`) + ), + ]; + const generatedContents = await Promise.all( + generatedFiles.map((file) => fs.readFile(file, 'utf-8')) + ); + + for (const content of generatedContents) { + expect(content).toContain( + 'treat `--store ` as sticky for the rest of the workflow' + ); + expect(content).toContain( + 'openspec status --change "" --json --store ""' + ); + } + + const updateVariants: Array<[string, string]> = [ + [ + await fs.readFile( + path.join( + testDir, + '.claude', + 'skills', + 'openspec-update-change', + 'SKILL.md' + ), + 'utf-8' + ), + '`/opsx:continue`', + ], + [ + await fs.readFile( + path.join(testDir, '.claude', 'commands', 'opsx', 'update.md'), + 'utf-8' + ), + '`/opsx:continue`', + ], + ]; + + for (const [content, continueReference] of updateVariants) { + const availabilityGuidance = content.indexOf( + `${continueReference} is an expanded-profile workflow and may not be installed` + ); + const nextReference = content.indexOf( + continueReference, + availabilityGuidance + continueReference.length + ); + + expect(availabilityGuidance).toBeGreaterThanOrEqual(0); + expect(content.indexOf(continueReference)).toBe(availabilityGuidance); + expect(nextReference).toBeGreaterThan(availabilityGuidance); + expect(content).toContain('openspec status --change "" --json'); + expect(content).toContain( + 'openspec instructions "" --change "" --json' + ); + } + + const syncFiles = [ + path.join(testDir, '.claude', 'skills', 'openspec-sync-specs', 'SKILL.md'), + path.join(testDir, '.claude', 'commands', 'opsx', 'sync.md'), + ]; + + for (const file of syncFiles) { + const content = await fs.readFile(file, 'utf-8'); + const mutationsComplete = content.indexOf( + 'Follow the **Main Spec Format Reference** below' + ); + const validation = content.indexOf('openspec validate --specs'); + const summary = content.indexOf('6. **Show summary**'); + + expect(mutationsComplete).toBeGreaterThanOrEqual(0); + expect(validation).toBeGreaterThan(mutationsComplete); + expect(summary).toBeGreaterThan(validation); + expect(content).toContain( + 'If validation fails, report the problems and do not claim the sync succeeded' + ); + } + }); + it('should create skills in Cursor skills directory', async () => { const initCommand = new InitCommand({ tools: 'cursor', force: true }); diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index 267a89b597..53a546389b 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -37,46 +37,46 @@ import { import { STORE_SELECTION_GUIDANCE } from '../../../src/core/templates/workflows/store-selection.js'; const EXPECTED_FUNCTION_HASHES: Record = { - getExploreSkillTemplate: '87ab8ad0914cdcb83332e0fa8bae4cfc887c2e21ad1acd1dbc1cde5c866912fe', - getNewChangeSkillTemplate: 'ede5485cb70e079039e16a410343389a3b6940df244a7cb8828b6aa478d16222', - getContinueChangeSkillTemplate: '98819c8e96053c330aa97929507aaec6070c517459cf21d81608cb320d6eee88', - getApplyChangeSkillTemplate: '38fac7eb01ac8113aebcb5421256a6ec5dd939c432d8062643f4e8ddcf66c019', - getFfChangeSkillTemplate: 'b29e80fe10c2d8393a6d01cf40eb1f684e18d2a5790c9bec3a890513abe72807', - getSyncSpecsSkillTemplate: 'df71a66661ea98a41cceacc40a12f2230c0bec7ee31a2408d2cfe4942c803a4d', - getOnboardSkillTemplate: '256acdc3f3321f0665df3a02cff7ee35782fa2242e9b05696684918f6be48428', - getOpsxExploreCommandTemplate: 'cd2ada418f8a3a972d7ba3030973a2e23a89de28ec8847454099c316b7d5b40b', - getOpsxNewCommandTemplate: '0955d26857221dae627530aeec3ce499b2ca898fe02232492c130c32d3e8a3d9', - getOpsxContinueCommandTemplate: '75b4407a0854a50be7bffe89348981d50146c438d2c31c06bd0c3d5ae21683d1', - getOpsxApplyCommandTemplate: 'd5d555e28e473b8601b283d220498f4fb51008f2831905f4da8a9fa7c2a9c1ea', - getOpsxFfCommandTemplate: 'a923f13c8e2219e69f6cd4214b2ea1733f4a539b0f0a142c5ec290d248aa1d24', - getArchiveChangeSkillTemplate: '99c4586fe8c9ea41f247a515faef19a2ca14621183f33805924c93012282e8c8', - getBulkArchiveChangeSkillTemplate: '3c7ab3ab67de25089071075fd4ae2095297aefd82a4785481a9c7dd4bb20c007', - getOpsxSyncCommandTemplate: '9f71518e562e8b6e171a4e24894d9bdd9650a7afb3c1a24807596f30245f48b8', - getVerifyChangeSkillTemplate: '65fc5b3f03921f4a645f0826b5637ccf4d6bd077ba27f3f510575cda739dff18', - getOpsxArchiveCommandTemplate: '8f25c5b87ddb246b6c6600486ecf195acfed30de653fe0a0f9e3d89136c66daf', - getOpsxOnboardCommandTemplate: '2626899ad0d459b71fe08565cbd60852ab4e2dccb001ecb1411bc7e45db0b4b9', - getOpsxBulkArchiveCommandTemplate: 'e76857b0ab1270c2730b45a3e10e9c392517fffa85061aebeade5067e7dd9d02', - getOpsxVerifyCommandTemplate: '5ed5c0707d25653205af13bd75c82bfcf8e4be48f29be6d0f10cf7c90a152bdb', - getOpsxProposeSkillTemplate: '1f4efb1439c6c0514088c09a1f5d43107bc209e888b197d3df6ae31a24044355', - getOpsxProposeCommandTemplate: 'b205fef794d5012b68b58b18af80f70fa9f3dde890f554aa1c8995bf2de6b74b', + getExploreSkillTemplate: 'fd45923f8d9eecb8896c17d5ce6d309302132e289132c680d5b3b4d6490501e8', + getNewChangeSkillTemplate: '935f6335e2d4b7d1bd4f0538c88386350c25e8b16e11b627556262229583ca51', + getContinueChangeSkillTemplate: '1354a92b54d8b3c0e6979c46e3bd3b0fb4e619c4a775ae9d33c1e4dc809d709d', + getApplyChangeSkillTemplate: 'e5fc093637d3100a61acf934553002a5e9f5bccab5110136d7680af4133f7351', + getFfChangeSkillTemplate: 'fc2a45a08533ee9c7ab30fdab5f832b7d440070048e2a153f03db1620dc379bb', + getSyncSpecsSkillTemplate: 'ea0f40684954115a38514556bbf7c9a1cec69b5f41ad75077c573f48b9fb0645', + getOnboardSkillTemplate: '0b0f9559e21e73a7acfb7e61b403b20080f10ba169d2330c6d55618ce1759a42', + getOpsxExploreCommandTemplate: '0f9af4120cfa7a8f273eebe7c0ddb56fd7c8705b28d1b1d48e1964a26b91d02f', + getOpsxNewCommandTemplate: '08e784e52ac2c146975a874257c589d88e93efbd83dc4d79253c8525f5c3064f', + getOpsxContinueCommandTemplate: 'a00664d4338219e85002f568756998ac4b7b53785d8fad2ff0c1261f3374ec44', + getOpsxApplyCommandTemplate: 'd879b0430f756b9dbc5a1a1348a34409b2fcd453eeae7add4bf9f421616c2ad1', + getOpsxFfCommandTemplate: '012610f85576a7055dfec2aaabba6bfc245454ce91fb6214587ae9316dc2b864', + getArchiveChangeSkillTemplate: 'a4aa35495747a78b9b8c45c72bdf644a227abcf3e219adee8803f9a4c7771879', + getBulkArchiveChangeSkillTemplate: 'bb76dcbfd329c815b8754dc018c5fe7be6ddc9ae680a190dfe01a5858d319e12', + getOpsxSyncCommandTemplate: 'b28949fa7ec13a1a55f822c82033e0a30651b7d4259c54515d42899a84f4c73d', + getVerifyChangeSkillTemplate: 'eb2c0f1b46c1be12750965a3a122efd5944d2b25781d714224c6e62a0efdc7fd', + getOpsxArchiveCommandTemplate: 'd817a5a44dda8dcca5de0eb67c16f9061d7f106a818138b7d8795fc810c62eb5', + getOpsxOnboardCommandTemplate: 'e04e4ab6c2f25122e6840212b4c22708812c36ceff9ec529c2bb1d1d035429e3', + getOpsxBulkArchiveCommandTemplate: 'cb1ab737abfe192212f0793ef67c203a83b30785a03ccac1bc4e9912cd17e560', + getOpsxVerifyCommandTemplate: 'ce0ee05b7a6b332e29db2298b9d5a928a1932caf516e35fd88f163154ffd43f4', + getOpsxProposeSkillTemplate: '6d098be13fc130b592427323dcbe505e865e54d2070cf9f8b7157890fdbaf77a', + getOpsxProposeCommandTemplate: '53eb694ac6a2cb865500b41c1bae45fc71016e40129ce10f9056f1b6068972d8', getFeedbackSkillTemplate: 'd7d83c5f7fc2b92fe8f4588a5bf2d9cb315e4c73ec19bcd5ef28270906319a0d', - getUpdateChangeSkillTemplate: '7ed22589fe4f655461d7b9d0fc5202414e75707184bcac5e42cee19dee559f8a', - getOpsxUpdateCommandTemplate: 'f5e47e21440dad17660983da17d3b933adfc5d08f1c049f2451f3de4c7b6136d', + getUpdateChangeSkillTemplate: 'f85fbfb3a175e949becbef08be0eccfab97de5e7ad45105e999d2900dfafbaba', + getOpsxUpdateCommandTemplate: '461edf06e92c0da3dab4f11d91d59d44b48ed30a0881c1f34a714b1813435af6', }; const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { - 'openspec-explore': 'b0abaad3c38653788d0463d5da6b90f9dab0433f420e1b78a6eebcf052a8ebd1', - 'openspec-new-change': '37150481c16edff989ea841257451dc0c22f4b16763794f2686983c32f1d66bd', - 'openspec-continue-change': '7c57f6303ba6b36b81119aaf7e515bd21f2864d90f9bd9586d453aa034d7d685', - 'openspec-apply-change': '5190dcbc86c1e8fc3bfc7b94ff023f0543ba435194c17f26d502621dd25f1820', - 'openspec-ff-change': 'f394c841ef796326382f113a7ca9003304b8c7189a8fb88d29981316987e1591', - 'openspec-sync-specs': '00d30e7fca274eb4faaeb23a75078fe51ede6e6329954f166baa9af011c177c4', - 'openspec-archive-change': '0654368ecec95ea37aa6e93441b7378a97b96cafe38a05304c0bb4f8120a81d4', - 'openspec-bulk-archive-change': 'd1331aec02d220cf36ca257b804cb4643ada0c0e68e3d593f01b993f88372bbd', - 'openspec-verify-change': 'c2d6d595cefde562696cd103137d76c80b3d13f6cb42c60d0c236523abdecbb3', - 'openspec-onboard': '384fd2ec91b4da7fa726f4dfd3f316b13277de02ac003417a428f1a12e400511', - 'openspec-propose': 'a54d3635ae1756be4733ae1bfe45984eaab253160f2d93d4be37a9c431b5662a', - 'openspec-update-change': '6394f32b4ac952f3713a35f56b721c05773a53d1a7dc710dc812814090f11166', + 'openspec-explore': '87a93d0d748c071982ed2199719f00b2885db94d4ac11ae9f12f79909777660c', + 'openspec-new-change': '579d432771703f947a331a6ed288bf9c6660ca015fcd376d76f19b6ac7683082', + 'openspec-continue-change': '06a8e9df0c34de6e90e067d6d17e8e361d48ec08adb57786bc63c41dd03529e8', + 'openspec-apply-change': '1726319cd4305a47f9c827acaeb84a9de57f7e44aba9ed60869c1758338e18ae', + 'openspec-ff-change': '19315644df7c582d920acfb67f3c500ca4e06fccc900265b3ac39621d85f7cdb', + 'openspec-sync-specs': '100d257802a3791b6c856c743dc5783611887c6ebf7ff7557cd209b235cc1bc8', + 'openspec-archive-change': 'bf640deb3ed48ff4aef26ee527bf0fbf56f2072119e6483119871f207ee3253e', + 'openspec-bulk-archive-change': '7115f6b452bd05fbce0ab04e58672a1ff1f480dfa143822f217646434623f256', + 'openspec-verify-change': '7cd65897d126f7c948620c0672ca62418620dbcb82ee73d890f758fb666a4ff8', + 'openspec-onboard': '80f39cf33a138aac8e508db25d7af2c9e9bd482f90e414770e806f966dd58c9c', + 'openspec-propose': '890f7c46e0ce7bbae5c8b214bd000d4c50c7d2f13aec1a55284c2fea77f13536', + 'openspec-update-change': '95bb533105e49aee06c9ea164b63092de77644cf8f94fa38d3ee3c11b0ccb893', }; // Intentionally excludes getFeedbackSkillTemplate: this list only models templates @@ -209,7 +209,10 @@ describe('skill templates split parity', () => { 'treat `--store ` as sticky for the rest of the workflow' ); expect(STORE_SELECTION_GUIDANCE).toContain( - 'append it to every applicable command below, even when the example does not repeat the flag' + 'Every unscoped example of those commands below is shorthand: before running it, append the flag' + ); + expect(STORE_SELECTION_GUIDANCE).toContain( + 'openspec status --change "" --json --store ""' ); expect(STORE_SELECTION_GUIDANCE).toContain('`context`, `view`'); }); @@ -221,10 +224,14 @@ describe('skill templates split parity', () => { ]; for (const [variant, content] of variants) { + const mutationsComplete = content.indexOf( + 'Follow the **Main Spec Format Reference** below' + ); const validation = content.indexOf('openspec validate --specs'); const summary = content.indexOf('**Show summary**'); - expect(validation, variant).toBeGreaterThanOrEqual(0); + expect(mutationsComplete, variant).toBeGreaterThanOrEqual(0); + expect(validation, variant).toBeGreaterThan(mutationsComplete); expect(summary, variant).toBeGreaterThan(validation); expect(content, variant).toContain('same selected-root flags'); expect(content, variant).toContain( diff --git a/test/core/templates/update-change.test.ts b/test/core/templates/update-change.test.ts index ef142c213e..94f52736bb 100644 --- a/test/core/templates/update-change.test.ts +++ b/test/core/templates/update-change.test.ts @@ -82,9 +82,13 @@ describe('update-change templates', () => { const availabilityGuidance = body.indexOf( '`/opsx:continue` is an expanded-profile workflow and may not be installed' ); - const firstSuggestion = body.indexOf('point the user to `/opsx:continue`'); + const firstSuggestion = body.indexOf( + '`/opsx:continue`', + availabilityGuidance + '`/opsx:continue`'.length + ); expect(availabilityGuidance, label).toBeGreaterThanOrEqual(0); + expect(body.indexOf('`/opsx:continue`'), label).toBe(availabilityGuidance); expect(firstSuggestion, label).toBeGreaterThan(availabilityGuidance); expect(body, label).toContain( 'If it is unavailable, `openspec status --change "" --json` shows the next artifact' @@ -101,13 +105,16 @@ describe('update-change templates', () => { expect(body, label).toContain('If the user rejects a revision, do not write it'); expect(body, label).toContain('recommend starting fresh with `/opsx:new`'); expect(body, label).toContain('Update vs. Start Fresh'); - expect(body, label).toContain('openspec new change ""'); + expect(body, label).toContain('ask for a distinct unused change name'); + expect(body, label).toContain('openspec new change ""'); + expect(body, label).not.toContain('openspec new change ""'); const newAvailabilityCheck = body.indexOf( 'first verify whether the expanded-profile `/opsx:new` workflow is available' ); const newRecommendation = body.indexOf('recommend starting fresh with `/opsx:new`'); expect(newAvailabilityCheck, label).toBeGreaterThanOrEqual(0); + expect(body.slice(0, newAvailabilityCheck), label).not.toContain('`/opsx:new`'); expect(newRecommendation, label).toBeGreaterThan(newAvailabilityCheck); } }); From 39d60c1e39eeb42d50efcff936b7323de2497788 Mon Sep 17 00:00:00 2001 From: Clay Good Date: Tue, 4 Aug 2026 14:32:46 -0500 Subject: [PATCH 5/5] test(templates): align parity hashes after rebase --- .../templates/skill-templates-parity.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index 53a546389b..4c07f70278 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -42,20 +42,20 @@ const EXPECTED_FUNCTION_HASHES: Record = { getContinueChangeSkillTemplate: '1354a92b54d8b3c0e6979c46e3bd3b0fb4e619c4a775ae9d33c1e4dc809d709d', getApplyChangeSkillTemplate: 'e5fc093637d3100a61acf934553002a5e9f5bccab5110136d7680af4133f7351', getFfChangeSkillTemplate: 'fc2a45a08533ee9c7ab30fdab5f832b7d440070048e2a153f03db1620dc379bb', - getSyncSpecsSkillTemplate: 'ea0f40684954115a38514556bbf7c9a1cec69b5f41ad75077c573f48b9fb0645', + getSyncSpecsSkillTemplate: 'f90032dbeb3a647b451139e12624753057018986df000159499dadc2c3d0965a', getOnboardSkillTemplate: '0b0f9559e21e73a7acfb7e61b403b20080f10ba169d2330c6d55618ce1759a42', getOpsxExploreCommandTemplate: '0f9af4120cfa7a8f273eebe7c0ddb56fd7c8705b28d1b1d48e1964a26b91d02f', getOpsxNewCommandTemplate: '08e784e52ac2c146975a874257c589d88e93efbd83dc4d79253c8525f5c3064f', getOpsxContinueCommandTemplate: 'a00664d4338219e85002f568756998ac4b7b53785d8fad2ff0c1261f3374ec44', getOpsxApplyCommandTemplate: 'd879b0430f756b9dbc5a1a1348a34409b2fcd453eeae7add4bf9f421616c2ad1', getOpsxFfCommandTemplate: '012610f85576a7055dfec2aaabba6bfc245454ce91fb6214587ae9316dc2b864', - getArchiveChangeSkillTemplate: 'a4aa35495747a78b9b8c45c72bdf644a227abcf3e219adee8803f9a4c7771879', - getBulkArchiveChangeSkillTemplate: 'bb76dcbfd329c815b8754dc018c5fe7be6ddc9ae680a190dfe01a5858d319e12', - getOpsxSyncCommandTemplate: 'b28949fa7ec13a1a55f822c82033e0a30651b7d4259c54515d42899a84f4c73d', + getArchiveChangeSkillTemplate: 'b6dac476db882d5e2afea237e298c2aa98ed9f9cacbcf1a5000f00e67e8ca524', + getBulkArchiveChangeSkillTemplate: 'da2bd729048acb64fbac46ab6a45b51174b1b1486f53cfb365499247f0cd4e18', + getOpsxSyncCommandTemplate: '2361cb11e0da0f3ecfded43441edaba8dab6c88ffeb0a217e60c9a3d446bef93', getVerifyChangeSkillTemplate: 'eb2c0f1b46c1be12750965a3a122efd5944d2b25781d714224c6e62a0efdc7fd', - getOpsxArchiveCommandTemplate: 'd817a5a44dda8dcca5de0eb67c16f9061d7f106a818138b7d8795fc810c62eb5', + getOpsxArchiveCommandTemplate: 'ce4f2863463a49e206cc6e51ca74e779a36c714e0b9a5233ac4d99535cb29101', getOpsxOnboardCommandTemplate: 'e04e4ab6c2f25122e6840212b4c22708812c36ceff9ec529c2bb1d1d035429e3', - getOpsxBulkArchiveCommandTemplate: 'cb1ab737abfe192212f0793ef67c203a83b30785a03ccac1bc4e9912cd17e560', + getOpsxBulkArchiveCommandTemplate: 'fbb4de58ed00861badd93cde9bdd3d7c52f966158a18a660152060076ea9723e', getOpsxVerifyCommandTemplate: 'ce0ee05b7a6b332e29db2298b9d5a928a1932caf516e35fd88f163154ffd43f4', getOpsxProposeSkillTemplate: '6d098be13fc130b592427323dcbe505e865e54d2070cf9f8b7157890fdbaf77a', getOpsxProposeCommandTemplate: '53eb694ac6a2cb865500b41c1bae45fc71016e40129ce10f9056f1b6068972d8', @@ -70,9 +70,9 @@ const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { 'openspec-continue-change': '06a8e9df0c34de6e90e067d6d17e8e361d48ec08adb57786bc63c41dd03529e8', 'openspec-apply-change': '1726319cd4305a47f9c827acaeb84a9de57f7e44aba9ed60869c1758338e18ae', 'openspec-ff-change': '19315644df7c582d920acfb67f3c500ca4e06fccc900265b3ac39621d85f7cdb', - 'openspec-sync-specs': '100d257802a3791b6c856c743dc5783611887c6ebf7ff7557cd209b235cc1bc8', - 'openspec-archive-change': 'bf640deb3ed48ff4aef26ee527bf0fbf56f2072119e6483119871f207ee3253e', - 'openspec-bulk-archive-change': '7115f6b452bd05fbce0ab04e58672a1ff1f480dfa143822f217646434623f256', + 'openspec-sync-specs': 'dbdc0528c5d59c1a9b3c8b3df01ab2bcf325ad2cb5d47e061c7a65106c058a3e', + 'openspec-archive-change': 'b7432016dd7f56e75da6c21945fa68f6946a4b20abb92788fe633850061e791c', + 'openspec-bulk-archive-change': 'c58e1d319a6587b52202434d5d769c94718aafc0f019276cef04cf8be473b6ce', 'openspec-verify-change': '7cd65897d126f7c948620c0672ca62418620dbcb82ee73d890f758fb666a4ff8', 'openspec-onboard': '80f39cf33a138aac8e508db25d7af2c9e9bd482f90e414770e806f966dd58c9c', 'openspec-propose': '890f7c46e0ce7bbae5c8b214bd000d4c50c7d2f13aec1a55284c2fea77f13536',