From f5ff932af109b92856eee49296844da5b1775e91 Mon Sep 17 00:00:00 2001 From: "Ayman D." Date: Sun, 23 Aug 2026 00:57:26 +0100 Subject: [PATCH 1/3] fix(explore): require explicit confirmation before writing files --- .changeset/explore-explicit-write-confirmation.md | 5 +++++ skills/openspec-explore/SKILL.md | 6 +++--- src/core/templates/workflows/explore.ts | 12 ++++++------ test/core/templates/skill-templates-parity.test.ts | 6 +++--- 4 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 .changeset/explore-explicit-write-confirmation.md diff --git a/.changeset/explore-explicit-write-confirmation.md b/.changeset/explore-explicit-write-confirmation.md new file mode 100644 index 0000000000..cf6119bbf5 --- /dev/null +++ b/.changeset/explore-explicit-write-confirmation.md @@ -0,0 +1,5 @@ +--- +'@fission-ai/openspec': patch +--- + +explore: require explicit confirmation before the skill writes any file. The explore skill's guardrails let "if the user asks" cover answers to its own clarifying questions, so an agent could treat a design discussion as a go-ahead and start creating schemas or editing `openspec/config.yaml` uninvited. The skill and the `/opsx:explore` command now instruct the agent to ask a direct yes/no question and wait for the user's confirmation in a separate message before the first write of any file, and the "Don't implement" guardrail now names workflow configuration — schemas, templates, `openspec/config.yaml` — as changes rather than thinking. diff --git a/skills/openspec-explore/SKILL.md b/skills/openspec-explore/SKILL.md index 327c261489..66df0bdd9a 100644 --- a/skills/openspec-explore/SKILL.md +++ b/skills/openspec-explore/SKILL.md @@ -11,7 +11,7 @@ metadata: Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing. For a new change, scaffold it first as described below. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before your first write of any file, ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation. For a new change, scaffold it first as described below. **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. @@ -296,11 +296,11 @@ But this summary is optional. Sometimes the thinking IS the value. ## Guardrails -- **Don't implement** - Never write code or implement features. Creating OpenSpec artifacts is fine, writing application code is not. +- **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or `openspec/config.yaml` is a change, not thinking. Creating OpenSpec artifacts once the user confirms is fine, writing anything else is not. - **Don't fake understanding** - If something is unclear, dig deeper - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally -- **Don't auto-capture** - Offer to save insights, don't just do it +- **Don't auto-capture** - Offer to save insights, don't just do it. Before your first write of ANY file (change artifacts, specs, `openspec/config.yaml`, `openspec/schemas/**`, anything else), ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. - **Don't manually scaffold changes** - Never create a new change directory under `openspec/changes/` by hand. Always use `openspec new change ""` (with `--store ` when applicable) so required metadata such as `.openspec.yaml` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality diff --git a/src/core/templates/workflows/explore.ts b/src/core/templates/workflows/explore.ts index 211de65646..cfdde1e3d0 100644 --- a/src/core/templates/workflows/explore.ts +++ b/src/core/templates/workflows/explore.ts @@ -13,7 +13,7 @@ export function getExploreSkillTemplate(): SkillTemplate { description: 'Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.', instructions: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing. For a new change, scaffold it first as described below. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before your first write of any file, ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation. For a new change, scaffold it first as described below. **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. @@ -298,11 +298,11 @@ But this summary is optional. Sometimes the thinking IS the value. ## Guardrails -- **Don't implement** - Never write code or implement features. Creating OpenSpec artifacts is fine, writing application code is not. +- **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating OpenSpec artifacts once the user confirms is fine, writing anything else is not. - **Don't fake understanding** - If something is unclear, dig deeper - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally -- **Don't auto-capture** - Offer to save insights, don't just do it +- **Don't auto-capture** - Offer to save insights, don't just do it. Before your first write of ANY file (change artifacts, specs, \`openspec/config.yaml\`, \`openspec/schemas/**\`, anything else), ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. - **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change ""\` (with \`--store \` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality @@ -321,7 +321,7 @@ export function getOpsxExploreCommandTemplate(): CommandTemplate { tags: ['workflow', 'explore', 'experimental', 'thinking'], content: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing. For a new change, scaffold it first as described below. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before your first write of any file, ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation. For a new change, scaffold it first as described below. **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. @@ -495,11 +495,11 @@ When things crystallize, you might offer a summary - but it's optional. Sometime ## Guardrails -- **Don't implement** - Never write code or implement features. Creating OpenSpec artifacts is fine, writing application code is not. +- **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating OpenSpec artifacts once the user confirms is fine, writing anything else is not. - **Don't fake understanding** - If something is unclear, dig deeper - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally -- **Don't auto-capture** - Offer to save insights, don't just do it +- **Don't auto-capture** - Offer to save insights, don't just do it. Before your first write of ANY file (change artifacts, specs, \`openspec/config.yaml\`, \`openspec/schemas/**\`, anything else), ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. - **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change ""\` (with \`--store \` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index 3860a62eda..f873f63203 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -38,14 +38,14 @@ import { import { STORE_SELECTION_GUIDANCE } from '../../../src/core/templates/workflows/store-selection.js'; const EXPECTED_FUNCTION_HASHES: Record = { - getExploreSkillTemplate: '3efc37cddf342318ac37be7bb4ff5915f454b4c5bb127294ebdc7534ee21aa23', + getExploreSkillTemplate: '401a3b7ba5cbeb81715db21864c4bf542ea25e51058a156ee8415f040ddcc3a7', getNewChangeSkillTemplate: 'eabd1e895c5881dcb17dcbaa3fb26098dd59e8eacb318e400820b4dc811ef781', getContinueChangeSkillTemplate: '012136f6411a99c8fa228e2f9444cb64b0a89e0f56fdeac2fe03b2f5bee0c5d7', getApplyChangeSkillTemplate: 'd1e7d5ceb85193c0964057dbb88e9651526754bd33f84020e2440ff0621d5dbb', getFfChangeSkillTemplate: '5501740e7ec36ab23ab8c3a0d6dd0655a5e2f35433c7b90e82904fef5e7a326a', getSyncSpecsSkillTemplate: 'b099e2ff31859c9b10d928066e662524f9aad9ecf2be12fceacb732d718c4146', getOnboardSkillTemplate: '3a836faae463d88c289a1c129cb7ee556a563b7e53e1a52a4711ff152a3b51f7', - getOpsxExploreCommandTemplate: 'd2f70d11588f902c15c1e5ce9908cc4124c6b82fe78dc766ac5c3599c9e2a6f1', + getOpsxExploreCommandTemplate: '92657ee1483d467dbf7db4ff5bfefbb19783a3fdde6206fe21d5c34f7e87bc59', getOpsxNewCommandTemplate: 'f2d30e569798a4c92ba932859d6ba4e0ad10e18feccbade1cfee0957597b3463', getOpsxContinueCommandTemplate: 'e50e50266efa1b8e64ff9b6274ee8254f0a240d6adc1b862d126e2f1c9d3a559', getOpsxApplyCommandTemplate: 'e3579ac78f2e2c75fa3d3a7ac7dc3e49c395e96f7323398f0f041d94f8de9bb0', @@ -66,7 +66,7 @@ const EXPECTED_FUNCTION_HASHES: Record = { }; const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { - 'openspec-explore': '4d9736372cc1faf8a5d8a66395a95bf77b9f3fcd2cda40411ad1db6927e8066a', + 'openspec-explore': '6ee737ed85cbe74bc1b35b1b86d98159cbd617b54013f6afaa4aff8be88305c3', 'openspec-new-change': 'ec4529beef978e34634a6f7286fab55d68fad8fb374dceb45691d52caab33fbb', 'openspec-continue-change': 'bb6194a16c54891cdb253678e8f70ce53b2af86735243980f366ce551d37e42e', 'openspec-apply-change': '81ea96d9fa6ec8536cd23c1fe561ed28e1cc1cad0a8ceb700588e08974cc0e49', From 4d2435e95f1de645a238ef28bdbc9c968c7c74c7 Mon Sep 17 00:00:00 2001 From: Clay Good Date: Mon, 24 Aug 2026 08:53:23 -0500 Subject: [PATCH 2/3] test(explore): harden write confirmation guardrail --- .../explore-explicit-write-confirmation.md | 2 +- skills/openspec-explore/SKILL.md | 4 +-- src/core/templates/workflows/explore.ts | 8 +++--- test/core/templates/explore.test.ts | 28 +++++++++++++++++++ .../templates/skill-templates-parity.test.ts | 6 ++-- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/.changeset/explore-explicit-write-confirmation.md b/.changeset/explore-explicit-write-confirmation.md index cf6119bbf5..b782d55b1c 100644 --- a/.changeset/explore-explicit-write-confirmation.md +++ b/.changeset/explore-explicit-write-confirmation.md @@ -2,4 +2,4 @@ '@fission-ai/openspec': patch --- -explore: require explicit confirmation before the skill writes any file. The explore skill's guardrails let "if the user asks" cover answers to its own clarifying questions, so an agent could treat a design discussion as a go-ahead and start creating schemas or editing `openspec/config.yaml` uninvited. The skill and the `/opsx:explore` command now instruct the agent to ask a direct yes/no question and wait for the user's confirmation in a separate message before the first write of any file, and the "Don't implement" guardrail now names workflow configuration — schemas, templates, `openspec/config.yaml` — as changes rather than thinking. +explore: require explicit confirmation before the skill uses any command or tool that can create, edit, move, or delete a file. The explore skill's guardrails let "if the user asks" cover answers to its own clarifying questions, so an agent could treat a design discussion as a go-ahead and start creating schemas or editing `openspec/config.yaml` uninvited. The skill and the `/opsx:explore` command now instruct the agent to ask a direct yes/no question and wait for the user's confirmation in a separate message before the first file-writing action, and the "Don't implement" guardrail now names workflow configuration — schemas, templates, `openspec/config.yaml` — as changes rather than thinking. diff --git a/skills/openspec-explore/SKILL.md b/skills/openspec-explore/SKILL.md index 66df0bdd9a..583eace7d6 100644 --- a/skills/openspec-explore/SKILL.md +++ b/skills/openspec-explore/SKILL.md @@ -11,7 +11,7 @@ metadata: Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before your first write of any file, ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation. For a new change, scaffold it first as described below. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before the first action that could create, edit, move, or delete a file (including running an OpenSpec command), ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation in a separate message. For a new change, scaffold it first as described below. **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. @@ -300,7 +300,7 @@ But this summary is optional. Sometimes the thinking IS the value. - **Don't fake understanding** - If something is unclear, dig deeper - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally -- **Don't auto-capture** - Offer to save insights, don't just do it. Before your first write of ANY file (change artifacts, specs, `openspec/config.yaml`, `openspec/schemas/**`, anything else), ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. +- **Don't auto-capture** - Offer to save insights, don't just do it. Before the first action that could create, edit, move, or delete ANY file—including running `openspec new change` or another command that writes files—ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. - **Don't manually scaffold changes** - Never create a new change directory under `openspec/changes/` by hand. Always use `openspec new change ""` (with `--store ` when applicable) so required metadata such as `.openspec.yaml` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality diff --git a/src/core/templates/workflows/explore.ts b/src/core/templates/workflows/explore.ts index cfdde1e3d0..d124b61f12 100644 --- a/src/core/templates/workflows/explore.ts +++ b/src/core/templates/workflows/explore.ts @@ -13,7 +13,7 @@ export function getExploreSkillTemplate(): SkillTemplate { description: 'Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.', instructions: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before your first write of any file, ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation. For a new change, scaffold it first as described below. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before the first action that could create, edit, move, or delete a file (including running an OpenSpec command), ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation in a separate message. For a new change, scaffold it first as described below. **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. @@ -302,7 +302,7 @@ But this summary is optional. Sometimes the thinking IS the value. - **Don't fake understanding** - If something is unclear, dig deeper - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally -- **Don't auto-capture** - Offer to save insights, don't just do it. Before your first write of ANY file (change artifacts, specs, \`openspec/config.yaml\`, \`openspec/schemas/**\`, anything else), ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. +- **Don't auto-capture** - Offer to save insights, don't just do it. Before the first action that could create, edit, move, or delete ANY file—including running \`openspec new change\` or another command that writes files—ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. - **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change ""\` (with \`--store \` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality @@ -321,7 +321,7 @@ export function getOpsxExploreCommandTemplate(): CommandTemplate { tags: ['workflow', 'explore', 'experimental', 'thinking'], content: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before your first write of any file, ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation. For a new change, scaffold it first as described below. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before the first action that could create, edit, move, or delete a file (including running an OpenSpec command), ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation in a separate message. For a new change, scaffold it first as described below. **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. @@ -499,7 +499,7 @@ When things crystallize, you might offer a summary - but it's optional. Sometime - **Don't fake understanding** - If something is unclear, dig deeper - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally -- **Don't auto-capture** - Offer to save insights, don't just do it. Before your first write of ANY file (change artifacts, specs, \`openspec/config.yaml\`, \`openspec/schemas/**\`, anything else), ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. +- **Don't auto-capture** - Offer to save insights, don't just do it. Before the first action that could create, edit, move, or delete ANY file—including running \`openspec new change\` or another command that writes files—ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. - **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change ""\` (with \`--store \` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality diff --git a/test/core/templates/explore.test.ts b/test/core/templates/explore.test.ts index 280077da83..333be29f38 100644 --- a/test/core/templates/explore.test.ts +++ b/test/core/templates/explore.test.ts @@ -80,6 +80,34 @@ describe('explore templates', () => { } }); + it('requires separate confirmation before any file-writing action (#1715)', () => { + for (const [label, body] of bodies) { + expect(body, label).toContain( + 'before the first action that could create, edit, move, or delete a file' + ); + expect(body, label).toContain('including running an OpenSpec command'); + expect(body, label).toContain('ask a direct yes/no question'); + expect(body, label).toContain("wait for the user's confirmation in a separate message"); + expect(body, label).toContain( + 'Answers to design or clarifying questions are never consent to write' + ); + } + }); + + it('treats workflow configuration and write-capable commands as changes (#1715)', () => { + for (const [label, body] of bodies) { + expect(body, label).toContain( + 'creating or editing schemas, templates, or `openspec/config.yaml` is a change' + ); + expect(body, label).toContain( + 'including running `openspec new change` or another command that writes files' + ); + expect(body, label).toContain( + 'Creating OpenSpec artifacts once the user confirms is fine, writing anything else is not' + ); + } + }); + it('scaffolds a new change before capturing exploration artifacts (#668, #720)', () => { for (const [label, body] of bodies) { const transition = newChangeTransition(body, label); diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index f873f63203..3c6a9fe725 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -38,14 +38,14 @@ import { import { STORE_SELECTION_GUIDANCE } from '../../../src/core/templates/workflows/store-selection.js'; const EXPECTED_FUNCTION_HASHES: Record = { - getExploreSkillTemplate: '401a3b7ba5cbeb81715db21864c4bf542ea25e51058a156ee8415f040ddcc3a7', + getExploreSkillTemplate: '38ef6b4817ff8e3583db52abb3422f864a71f42f5d76e6b1f7c67463010e51b2', getNewChangeSkillTemplate: 'eabd1e895c5881dcb17dcbaa3fb26098dd59e8eacb318e400820b4dc811ef781', getContinueChangeSkillTemplate: '012136f6411a99c8fa228e2f9444cb64b0a89e0f56fdeac2fe03b2f5bee0c5d7', getApplyChangeSkillTemplate: 'd1e7d5ceb85193c0964057dbb88e9651526754bd33f84020e2440ff0621d5dbb', getFfChangeSkillTemplate: '5501740e7ec36ab23ab8c3a0d6dd0655a5e2f35433c7b90e82904fef5e7a326a', getSyncSpecsSkillTemplate: 'b099e2ff31859c9b10d928066e662524f9aad9ecf2be12fceacb732d718c4146', getOnboardSkillTemplate: '3a836faae463d88c289a1c129cb7ee556a563b7e53e1a52a4711ff152a3b51f7', - getOpsxExploreCommandTemplate: '92657ee1483d467dbf7db4ff5bfefbb19783a3fdde6206fe21d5c34f7e87bc59', + getOpsxExploreCommandTemplate: '060150041cd075ae160abeaea426040e19b6c3bd80ae93f8cb541c33b8a532e0', getOpsxNewCommandTemplate: 'f2d30e569798a4c92ba932859d6ba4e0ad10e18feccbade1cfee0957597b3463', getOpsxContinueCommandTemplate: 'e50e50266efa1b8e64ff9b6274ee8254f0a240d6adc1b862d126e2f1c9d3a559', getOpsxApplyCommandTemplate: 'e3579ac78f2e2c75fa3d3a7ac7dc3e49c395e96f7323398f0f041d94f8de9bb0', @@ -66,7 +66,7 @@ const EXPECTED_FUNCTION_HASHES: Record = { }; const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { - 'openspec-explore': '6ee737ed85cbe74bc1b35b1b86d98159cbd617b54013f6afaa4aff8be88305c3', + 'openspec-explore': 'c9591a8ca08eaae598da619a9153e53487229f0507cccf710f5e2ac983db16b1', 'openspec-new-change': 'ec4529beef978e34634a6f7286fab55d68fad8fb374dceb45691d52caab33fbb', 'openspec-continue-change': 'bb6194a16c54891cdb253678e8f70ce53b2af86735243980f366ce551d37e42e', 'openspec-apply-change': '81ea96d9fa6ec8536cd23c1fe561ed28e1cc1cad0a8ceb700588e08974cc0e49', From 62ef54f4e4fcf4efed2082798e5162f96f7c429a Mon Sep 17 00:00:00 2001 From: Clay Good Date: Mon, 24 Aug 2026 10:22:23 -0500 Subject: [PATCH 3/3] fix(explore): scope write confirmation precisely --- .changeset/explore-explicit-write-confirmation.md | 2 +- skills/openspec-explore/SKILL.md | 6 +++--- src/core/templates/workflows/explore.ts | 12 ++++++------ test/core/templates/explore.test.ts | 14 +++++++++----- test/core/templates/skill-templates-parity.test.ts | 6 +++--- 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/.changeset/explore-explicit-write-confirmation.md b/.changeset/explore-explicit-write-confirmation.md index b782d55b1c..cc07a77e23 100644 --- a/.changeset/explore-explicit-write-confirmation.md +++ b/.changeset/explore-explicit-write-confirmation.md @@ -2,4 +2,4 @@ '@fission-ai/openspec': patch --- -explore: require explicit confirmation before the skill uses any command or tool that can create, edit, move, or delete a file. The explore skill's guardrails let "if the user asks" cover answers to its own clarifying questions, so an agent could treat a design discussion as a go-ahead and start creating schemas or editing `openspec/config.yaml` uninvited. The skill and the `/opsx:explore` command now instruct the agent to ask a direct yes/no question and wait for the user's confirmation in a separate message before the first file-writing action, and the "Don't implement" guardrail now names workflow configuration — schemas, templates, `openspec/config.yaml` — as changes rather than thinking. +explore: require explicit, scope-bound confirmation before the skill uses any command or tool that can create, edit, move, or delete a file. The explore skill's guardrails let "if the user asks" cover answers to its own clarifying questions, so an agent could treat a design discussion as a go-ahead and start creating schemas or editing `openspec/config.yaml` uninvited. The skill and the `/opsx:explore` command now instruct the agent to name the proposed artifacts or files, ask a direct yes/no question, and wait for confirmation in a separate message before writing. Read-only commands and tools remain available without confirmation, and expanding the confirmed scope requires another confirmation. diff --git a/skills/openspec-explore/SKILL.md b/skills/openspec-explore/SKILL.md index 583eace7d6..706552004e 100644 --- a/skills/openspec-explore/SKILL.md +++ b/skills/openspec-explore/SKILL.md @@ -11,7 +11,7 @@ metadata: Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before the first action that could create, edit, move, or delete a file (including running an OpenSpec command), ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation in a separate message. For a new change, scaffold it first as described below. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, investigate the codebase, and run read-only commands or tools without confirmation, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create or update OpenSpec change artifacts (proposals, designs, specs) within a confirmed scope—that's capturing thinking, not implementing. Answering design or clarifying questions is never consent to write. Before the first write-capable action, name the artifacts or files you would change and what you would do, ask a direct yes/no question, and wait for the user's confirmation in a separate message. Confirmation covers only the scope you described; ask again before expanding it. For a new change, scaffold it first as described below. **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. @@ -296,11 +296,11 @@ But this summary is optional. Sometimes the thinking IS the value. ## Guardrails -- **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or `openspec/config.yaml` is a change, not thinking. Creating OpenSpec artifacts once the user confirms is fine, writing anything else is not. +- **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or `openspec/config.yaml` is a change, not thinking. Creating or updating OpenSpec change artifacts within the confirmed scope is fine, writing anything else is not. - **Don't fake understanding** - If something is unclear, dig deeper - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally -- **Don't auto-capture** - Offer to save insights, don't just do it. Before the first action that could create, edit, move, or delete ANY file—including running `openspec new change` or another command that writes files—ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. +- **Don't auto-capture** - Offer to save insights, don't just do it. Read-only commands and tools need no confirmation. Before the first write-capable action—including `openspec new change` or another command that writes files—name the artifacts or files and proposed changes, ask a direct yes/no question, and wait for explicit confirmation in a separate user message. That confirmation covers only the described scope; ask again before expanding it. Answers to design or clarifying questions are never consent to write. - **Don't manually scaffold changes** - Never create a new change directory under `openspec/changes/` by hand. Always use `openspec new change ""` (with `--store ` when applicable) so required metadata such as `.openspec.yaml` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality diff --git a/src/core/templates/workflows/explore.ts b/src/core/templates/workflows/explore.ts index d124b61f12..e9c72e5744 100644 --- a/src/core/templates/workflows/explore.ts +++ b/src/core/templates/workflows/explore.ts @@ -13,7 +13,7 @@ export function getExploreSkillTemplate(): SkillTemplate { description: 'Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.', instructions: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before the first action that could create, edit, move, or delete a file (including running an OpenSpec command), ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation in a separate message. For a new change, scaffold it first as described below. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, investigate the codebase, and run read-only commands or tools without confirmation, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create or update OpenSpec change artifacts (proposals, designs, specs) within a confirmed scope—that's capturing thinking, not implementing. Answering design or clarifying questions is never consent to write. Before the first write-capable action, name the artifacts or files you would change and what you would do, ask a direct yes/no question, and wait for the user's confirmation in a separate message. Confirmation covers only the scope you described; ask again before expanding it. For a new change, scaffold it first as described below. **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. @@ -298,11 +298,11 @@ But this summary is optional. Sometimes the thinking IS the value. ## Guardrails -- **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating OpenSpec artifacts once the user confirms is fine, writing anything else is not. +- **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating or updating OpenSpec change artifacts within the confirmed scope is fine, writing anything else is not. - **Don't fake understanding** - If something is unclear, dig deeper - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally -- **Don't auto-capture** - Offer to save insights, don't just do it. Before the first action that could create, edit, move, or delete ANY file—including running \`openspec new change\` or another command that writes files—ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. +- **Don't auto-capture** - Offer to save insights, don't just do it. Read-only commands and tools need no confirmation. Before the first write-capable action—including \`openspec new change\` or another command that writes files—name the artifacts or files and proposed changes, ask a direct yes/no question, and wait for explicit confirmation in a separate user message. That confirmation covers only the described scope; ask again before expanding it. Answers to design or clarifying questions are never consent to write. - **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change ""\` (with \`--store \` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality @@ -321,7 +321,7 @@ export function getOpsxExploreCommandTemplate(): CommandTemplate { tags: ['workflow', 'explore', 'experimental', 'thinking'], content: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) when the user explicitly asks you to—that's capturing thinking, not implementing. Answering design or clarifying questions is never such an ask: before the first action that could create, edit, move, or delete a file (including running an OpenSpec command), ask a direct yes/no question ("Want me to create it?") and wait for the user's confirmation in a separate message. For a new change, scaffold it first as described below. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, investigate the codebase, and run read-only commands or tools without confirmation, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create or update OpenSpec change artifacts (proposals, designs, specs) within a confirmed scope—that's capturing thinking, not implementing. Answering design or clarifying questions is never consent to write. Before the first write-capable action, name the artifacts or files you would change and what you would do, ask a direct yes/no question, and wait for the user's confirmation in a separate message. Confirmation covers only the scope you described; ask again before expanding it. For a new change, scaffold it first as described below. **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. @@ -495,11 +495,11 @@ When things crystallize, you might offer a summary - but it's optional. Sometime ## Guardrails -- **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating OpenSpec artifacts once the user confirms is fine, writing anything else is not. +- **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating or updating OpenSpec change artifacts within the confirmed scope is fine, writing anything else is not. - **Don't fake understanding** - If something is unclear, dig deeper - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally -- **Don't auto-capture** - Offer to save insights, don't just do it. Before the first action that could create, edit, move, or delete ANY file—including running \`openspec new change\` or another command that writes files—ask a direct yes/no question and wait for explicit confirmation in a separate user message. Answers to design or clarifying questions are never consent to write. +- **Don't auto-capture** - Offer to save insights, don't just do it. Read-only commands and tools need no confirmation. Before the first write-capable action—including \`openspec new change\` or another command that writes files—name the artifacts or files and proposed changes, ask a direct yes/no question, and wait for explicit confirmation in a separate user message. That confirmation covers only the described scope; ask again before expanding it. Answers to design or clarifying questions are never consent to write. - **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change ""\` (with \`--store \` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality diff --git a/test/core/templates/explore.test.ts b/test/core/templates/explore.test.ts index 333be29f38..71f6a1b9dc 100644 --- a/test/core/templates/explore.test.ts +++ b/test/core/templates/explore.test.ts @@ -83,13 +83,17 @@ describe('explore templates', () => { it('requires separate confirmation before any file-writing action (#1715)', () => { for (const [label, body] of bodies) { expect(body, label).toContain( - 'before the first action that could create, edit, move, or delete a file' + 'Before the first write-capable action' ); - expect(body, label).toContain('including running an OpenSpec command'); + expect(body, label).toContain('name the artifacts or files you would change'); expect(body, label).toContain('ask a direct yes/no question'); expect(body, label).toContain("wait for the user's confirmation in a separate message"); expect(body, label).toContain( - 'Answers to design or clarifying questions are never consent to write' + 'Answering design or clarifying questions is never consent to write' + ); + expect(body, label).toContain('run read-only commands or tools without confirmation'); + expect(body, label).toContain( + 'Confirmation covers only the scope you described; ask again before expanding it' ); } }); @@ -100,10 +104,10 @@ describe('explore templates', () => { 'creating or editing schemas, templates, or `openspec/config.yaml` is a change' ); expect(body, label).toContain( - 'including running `openspec new change` or another command that writes files' + 'including `openspec new change` or another command that writes files' ); expect(body, label).toContain( - 'Creating OpenSpec artifacts once the user confirms is fine, writing anything else is not' + 'Creating or updating OpenSpec change artifacts within the confirmed scope is fine, writing anything else is not' ); } }); diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index 3c6a9fe725..e7bee01f34 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -38,14 +38,14 @@ import { import { STORE_SELECTION_GUIDANCE } from '../../../src/core/templates/workflows/store-selection.js'; const EXPECTED_FUNCTION_HASHES: Record = { - getExploreSkillTemplate: '38ef6b4817ff8e3583db52abb3422f864a71f42f5d76e6b1f7c67463010e51b2', + getExploreSkillTemplate: 'cf59415faf8fe340b02a83e6d1267b8fabe78a9ee6d3856353daa5cb09c54279', getNewChangeSkillTemplate: 'eabd1e895c5881dcb17dcbaa3fb26098dd59e8eacb318e400820b4dc811ef781', getContinueChangeSkillTemplate: '012136f6411a99c8fa228e2f9444cb64b0a89e0f56fdeac2fe03b2f5bee0c5d7', getApplyChangeSkillTemplate: 'd1e7d5ceb85193c0964057dbb88e9651526754bd33f84020e2440ff0621d5dbb', getFfChangeSkillTemplate: '5501740e7ec36ab23ab8c3a0d6dd0655a5e2f35433c7b90e82904fef5e7a326a', getSyncSpecsSkillTemplate: 'b099e2ff31859c9b10d928066e662524f9aad9ecf2be12fceacb732d718c4146', getOnboardSkillTemplate: '3a836faae463d88c289a1c129cb7ee556a563b7e53e1a52a4711ff152a3b51f7', - getOpsxExploreCommandTemplate: '060150041cd075ae160abeaea426040e19b6c3bd80ae93f8cb541c33b8a532e0', + getOpsxExploreCommandTemplate: '6d7031b7801b25eb4698831b9f07d1d0ace394f56e9197a8deea3f4cb7194b22', getOpsxNewCommandTemplate: 'f2d30e569798a4c92ba932859d6ba4e0ad10e18feccbade1cfee0957597b3463', getOpsxContinueCommandTemplate: 'e50e50266efa1b8e64ff9b6274ee8254f0a240d6adc1b862d126e2f1c9d3a559', getOpsxApplyCommandTemplate: 'e3579ac78f2e2c75fa3d3a7ac7dc3e49c395e96f7323398f0f041d94f8de9bb0', @@ -66,7 +66,7 @@ const EXPECTED_FUNCTION_HASHES: Record = { }; const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { - 'openspec-explore': 'c9591a8ca08eaae598da619a9153e53487229f0507cccf710f5e2ac983db16b1', + 'openspec-explore': '39d8f9052d752f2618d5c7c11010435309775e310d2f245b4eb0f3f4830e594f', 'openspec-new-change': 'ec4529beef978e34634a6f7286fab55d68fad8fb374dceb45691d52caab33fbb', 'openspec-continue-change': 'bb6194a16c54891cdb253678e8f70ce53b2af86735243980f366ce551d37e42e', 'openspec-apply-change': '81ea96d9fa6ec8536cd23c1fe561ed28e1cc1cad0a8ceb700588e08974cc0e49',