From 1f7c50efea04ae53279ab86787ee97b844767456 Mon Sep 17 00:00:00 2001 From: Clay Good Date: Wed, 15 Jul 2026 10:35:36 -0500 Subject: [PATCH] fix(templates): re-read dependency artifacts from disk before creating the next one The continue/propose/ff workflow instructions said to "read dependency files for context," but an agent that already saw those files earlier in the session treats them as read and regenerates downstream artifacts from its stale in-context copy. Editing spec.md and deleting design.md/tasks.md to regenerate them silently produced artifacts based on the pre-edit spec. The step guidance, the guardrails, and the `openspec instructions` dependency block now say explicitly: re-read dependency files from disk even if seen earlier in the conversation, because the user may have edited them. Discussion: https://github.com/Fission-AI/OpenSpec/discussions/909 Co-Authored-By: Claude Fable 5 --- .../reread-dependencies-before-regenerating.md | 7 +++++++ src/commands/workflow/instructions.ts | 2 +- .../templates/workflows/continue-change.ts | 8 ++++---- src/core/templates/workflows/ff-change.ts | 8 ++++---- src/core/templates/workflows/propose.ts | 8 ++++---- .../templates/skill-templates-parity.test.ts | 18 +++++++++--------- 6 files changed, 29 insertions(+), 22 deletions(-) create mode 100644 .changeset/reread-dependencies-before-regenerating.md diff --git a/.changeset/reread-dependencies-before-regenerating.md b/.changeset/reread-dependencies-before-regenerating.md new file mode 100644 index 0000000000..6fd81540f9 --- /dev/null +++ b/.changeset/reread-dependencies-before-regenerating.md @@ -0,0 +1,7 @@ +--- +"@fission-ai/openspec": patch +--- + +### Fixes + +- **Regenerated artifacts now pick up your manual edits** — the continue, propose, and fast-forward workflows (and the `openspec instructions` dependency block) now tell the agent to re-read dependency artifacts from disk before creating the next one, instead of trusting whatever version it saw earlier in the conversation. Previously, editing `spec.md` and deleting `design.md`/`tasks.md` to regenerate them could silently produce artifacts based on the stale, pre-edit content. diff --git a/src/commands/workflow/instructions.ts b/src/commands/workflow/instructions.ts index 10a5fac166..8be371c45c 100644 --- a/src/commands/workflow/instructions.ts +++ b/src/commands/workflow/instructions.ts @@ -235,7 +235,7 @@ export function printInstructionsText(instructions: ArtifactInstructions, isBloc // Dependencies (files to read for context) if (dependencies.length > 0) { console.log(''); - console.log('Read these files for context before creating this artifact:'); + console.log('Read the current contents of these files before creating this artifact (re-read them from disk even if you saw them earlier - they may have been edited):'); console.log(); for (const dep of dependencies) { const status = dep.done ? 'done' : 'missing'; diff --git a/src/core/templates/workflows/continue-change.ts b/src/core/templates/workflows/continue-change.ts index 50e5a5c7f6..7af550422c 100644 --- a/src/core/templates/workflows/continue-change.ts +++ b/src/core/templates/workflows/continue-change.ts @@ -69,7 +69,7 @@ ${STORE_SELECTION_GUIDANCE} - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read for context - **Create the artifact file**: - - Read any completed dependency files for context + - Read any completed dependency files for context - always re-read them from disk, even if you saw them earlier in the conversation (the user may have edited them) - Use \`template\` as the structure - fill in its sections - Apply \`context\` and \`rules\` as constraints when writing - but do NOT copy them into the file - Write to the \`resolvedOutputPath\` specified in instructions. If it is a glob pattern, choose the concrete file path using the schema instruction and the change's context @@ -113,7 +113,7 @@ For other schemas, follow the \`instruction\` field from the CLI output. **Guardrails** - Create ONE artifact per invocation -- Always read dependency artifacts before creating a new one +- Always read dependency artifacts before creating a new one - re-read from disk, not from conversation memory (files may have changed since you last saw them) - Never skip artifacts or create out of order - If context is unclear, ask the user before creating - Verify the artifact file exists after writing before marking progress @@ -191,7 +191,7 @@ ${STORE_SELECTION_GUIDANCE} - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read for context - **Create the artifact file**: - - Read any completed dependency files for context + - Read any completed dependency files for context - always re-read them from disk, even if you saw them earlier in the conversation (the user may have edited them) - Use \`template\` as the structure - fill in its sections - Apply \`context\` and \`rules\` as constraints when writing - but do NOT copy them into the file - Write to the \`resolvedOutputPath\` specified in instructions. If it is a glob pattern, choose the concrete file path using the schema instruction and the change's context @@ -235,7 +235,7 @@ For other schemas, follow the \`instruction\` field from the CLI output. **Guardrails** - Create ONE artifact per invocation -- Always read dependency artifacts before creating a new one +- Always read dependency artifacts before creating a new one - re-read from disk, not from conversation memory (files may have changed since you last saw them) - Never skip artifacts or create out of order - If context is unclear, ask the user before creating - Verify the artifact file exists after writing before marking progress diff --git a/src/core/templates/workflows/ff-change.ts b/src/core/templates/workflows/ff-change.ts index fafcd85eba..16551a6bb8 100644 --- a/src/core/templates/workflows/ff-change.ts +++ b/src/core/templates/workflows/ff-change.ts @@ -61,7 +61,7 @@ ${STORE_SELECTION_GUIDANCE} - \`instruction\`: Schema-specific guidance for this artifact type - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read for context - - Read any completed dependency files for context + - Read any completed dependency files for context - always re-read them from disk, even if you saw them earlier in the conversation (the user may have edited them) - Create the artifact file using \`template\` as the structure and write it to \`resolvedOutputPath\` - Apply \`context\` and \`rules\` as constraints - but do NOT copy them into the file - Show brief progress: "✓ Created " @@ -100,7 +100,7 @@ After completing all artifacts, summarize: **Guardrails** - Create ALL artifacts needed for implementation (as defined by schema's \`apply.requires\`) -- Always read dependency artifacts before creating a new one +- Always read dependency artifacts before creating a new one - re-read from disk, not from conversation memory (files may have changed since you last saw them) - If context is critically unclear, ask the user - but prefer making reasonable decisions to keep momentum - If a change with that name already exists, suggest continuing that change instead - Verify each artifact file exists after writing before proceeding to next`, @@ -166,7 +166,7 @@ ${STORE_SELECTION_GUIDANCE} - \`instruction\`: Schema-specific guidance for this artifact type - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read for context - - Read any completed dependency files for context + - Read any completed dependency files for context - always re-read them from disk, even if you saw them earlier in the conversation (the user may have edited them) - Create the artifact file using \`template\` as the structure and write it to \`resolvedOutputPath\` - Apply \`context\` and \`rules\` as constraints - but do NOT copy them into the file - Show brief progress: "✓ Created " @@ -205,7 +205,7 @@ After completing all artifacts, summarize: **Guardrails** - Create ALL artifacts needed for implementation (as defined by schema's \`apply.requires\`) -- Always read dependency artifacts before creating a new one +- Always read dependency artifacts before creating a new one - re-read from disk, not from conversation memory (files may have changed since you last saw them) - If context is critically unclear, ask the user - but prefer making reasonable decisions to keep momentum - If a change with that name already exists, ask if user wants to continue it or create a new one - Verify each artifact file exists after writing before proceeding to next` diff --git a/src/core/templates/workflows/propose.ts b/src/core/templates/workflows/propose.ts index d84dab5a85..5f5ee8114b 100644 --- a/src/core/templates/workflows/propose.ts +++ b/src/core/templates/workflows/propose.ts @@ -70,7 +70,7 @@ ${STORE_SELECTION_GUIDANCE} - \`instruction\`: Schema-specific guidance for this artifact type - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read for context - - Read any completed dependency files for context + - Read any completed dependency files for context - always re-read them from disk, even if you saw them earlier in the conversation (the user may have edited them) - Create the artifact file using \`template\` as the structure and write it to \`resolvedOutputPath\` - Apply \`context\` and \`rules\` as constraints - but do NOT copy them into the file - Show brief progress: "Created " @@ -109,7 +109,7 @@ After completing all artifacts, summarize: **Guardrails** - Create ALL artifacts needed for implementation (as defined by schema's \`apply.requires\`) -- Always read dependency artifacts before creating a new one +- Always read dependency artifacts before creating a new one - re-read from disk, not from conversation memory (files may have changed since you last saw them) - If context is critically unclear, ask the user - but prefer making reasonable decisions to keep momentum - If a change with that name already exists, ask if user wants to continue it or create a new one - Verify each artifact file exists after writing before proceeding to next`, @@ -184,7 +184,7 @@ ${STORE_SELECTION_GUIDANCE} - \`instruction\`: Schema-specific guidance for this artifact type - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read for context - - Read any completed dependency files for context + - Read any completed dependency files for context - always re-read them from disk, even if you saw them earlier in the conversation (the user may have edited them) - Create the artifact file using \`template\` as the structure and write it to \`resolvedOutputPath\` - Apply \`context\` and \`rules\` as constraints - but do NOT copy them into the file - Show brief progress: "Created " @@ -223,7 +223,7 @@ After completing all artifacts, summarize: **Guardrails** - Create ALL artifacts needed for implementation (as defined by schema's \`apply.requires\`) -- Always read dependency artifacts before creating a new one +- Always read dependency artifacts before creating a new one - re-read from disk, not from conversation memory (files may have changed since you last saw them) - If context is critically unclear, ask the user - but prefer making reasonable decisions to keep momentum - If a change with that name already exists, ask if user wants to continue it or create a new one - Verify each artifact file exists after writing before proceeding to next` diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index 65202e9e6e..7b5d4f74a7 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -39,16 +39,16 @@ import { STORE_SELECTION_GUIDANCE } from '../../../src/core/templates/workflows/ const EXPECTED_FUNCTION_HASHES: Record = { getExploreSkillTemplate: '7d2f54e74fffcb36aaaa4498a4a8b033142bb25945fb9b2de532354acbe76b9c', getNewChangeSkillTemplate: '39663a6d2037e6697020393a66f6327506e3e3bc573b7a3556dcb7f9457dc51d', - getContinueChangeSkillTemplate: '1bb28875d6e5946ea2ec5f12e90f55d9784c2fa1f6e4c4e2d0eda53d861d4c75', + getContinueChangeSkillTemplate: 'acc07a489a30192b4bf2bbdc587a889478fbf6fffbbc9353c7775c4ca1ec5011', getApplyChangeSkillTemplate: '0f5a15fc7fb9ad6059a5643d0e01365d27642637a4aaebf182f9eabb45348197', - getFfChangeSkillTemplate: '9f4c12a1c58c723c9c45a139307eb90caf39cedd93c435bc960d0817328875e2', + getFfChangeSkillTemplate: '20ebb682ba89809a100cd4985c074908df5bada2bd649ca1b0f4059a63a1c728', getSyncSpecsSkillTemplate: '75abb20572256e2b8a647e77befae99f109ab5c4dc954a9c3c184829b5fcaa40', getOnboardSkillTemplate: 'e871d8ce172bb805ae62a7611aee7a3154d89414f427ad5ef31721c903f13002', getOpsxExploreCommandTemplate: '37e53590aae7ac6621d4393aa80a5b8af21881323887fa924ed329199fda27e0', getOpsxNewCommandTemplate: '57c600cce318d16b9b4308a18d0d983ea3c0673034e606a7cceec07b4c705e87', - getOpsxContinueCommandTemplate: '418108b417107a87019d4020b26c105792d2ef0110fe6920445e255889216716', + getOpsxContinueCommandTemplate: 'f63964fab7720ede097aa48808baff196c391b962930ca960459205c724800e5', getOpsxApplyCommandTemplate: 'daeb507206707169de73c828e199648dde5732cbc17791ef2a027adffd028574', - getOpsxFfCommandTemplate: '36973ae0dd00ab169fbaaa42bf565f97e1bc97cf63ae7c07307734cc1ca8c1fd', + getOpsxFfCommandTemplate: 'b859b1955cda6012877ae7f9ec6980e468f2e949a3838dfcdebc17209d133749', getArchiveChangeSkillTemplate: 'c511a1c943bcfc5f9f3833b8c0ff284b22d34864a08f5f553cec471ee485d38f', getBulkArchiveChangeSkillTemplate: '0f635913757ae3d1609e111f4a8f699443ca47cbaaf8a1b21eb652f7b96a1d13', getOpsxSyncCommandTemplate: '86cf706886d0f18069e2cfa16948b7357028fd348210efb58588c88c416d8622', @@ -57,8 +57,8 @@ const EXPECTED_FUNCTION_HASHES: Record = { getOpsxOnboardCommandTemplate: '0673f34a0f81fd173bcfb8c3ac83e2b1c617f7b7564e24e5298d3bd5665a05a9', getOpsxBulkArchiveCommandTemplate: '9f444fc7b27a5b788077b5e3aa4f61af45aa8c8004ac8d899d204fa362ff89b7', getOpsxVerifyCommandTemplate: '011509480a20a60342c993906f0f9280c0e9ba5d019d335bdc1ef4d53213a5a8', - getOpsxProposeSkillTemplate: '8dfb5e9c719d5ba547aff0d3953c076dca6b33d7223be98cbffc396b8f1e0048', - getOpsxProposeCommandTemplate: '7cd569beb32d99cdabd0b49615a8245160a8e152b6ea67a99fc4dd71e3f39f50', + getOpsxProposeSkillTemplate: '59197064a46c53264b62925a1c725af4ebe7caf9f0eaed4101990b7c13a40db1', + getOpsxProposeCommandTemplate: '04f808a36e850b9cdbc4f943ef324a9fd2b1b0cc59b92f127ab6cc452d66cc4e', getFeedbackSkillTemplate: 'd7d83c5f7fc2b92fe8f4588a5bf2d9cb315e4c73ec19bcd5ef28270906319a0d', getUpdateChangeSkillTemplate: 'fe2e8edaf973d42dc7fc7dfd846105c4c3cfec0437606e582ec644985cd4e81d', getOpsxUpdateCommandTemplate: 'e55ac5774203a7d9037d2d588889c97c53f3f930da49497cc79e865375920da7', @@ -67,15 +67,15 @@ const EXPECTED_FUNCTION_HASHES: Record = { const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { 'openspec-explore': 'ba099821631ce75ee70af370917bbddbc88d0882ad0e50e91ed687d2185102ef', 'openspec-new-change': 'd5b8909bea70a33b7a312b38ce204a91f40b6bb2bff12c4c06b3e11641b6a689', - 'openspec-continue-change': '39b4467a4873cde7c97d52c80d53ac647b220bf7c9d96f4e6505f3188e1a1642', + 'openspec-continue-change': 'bdb8bbb6a768a741b05256effbc284d65ac6a45360b59c24b94198792d3d0ebf', 'openspec-apply-change': '09c0e1cdf5ccc82416d0969d6bd715cc70616bdbc3531358a5c36057f78be55a', - 'openspec-ff-change': '8d5a8890eccbd97d714fbab1d73472f79ad9104b519e000264ae43d752cdf631', + 'openspec-ff-change': '0c82830cd9bc98f86eb56b63ddaabe2bf5d35fe25b6c40a7059311aee2c8acac', 'openspec-sync-specs': 'f6a1581eb11a30061795c42582db6fa4f5e1f213b4b7cad9f3cbfbe3e9fb2d97', 'openspec-archive-change': '1821aee5a06afd895d59d1e1d16495e484b6087ecf59ec93460d7d5e7851e772', 'openspec-bulk-archive-change': '7b09b04a440809dd7dbf0b1d7b695cbb8c41184d8d104eb32e82d7cdfb476d18', 'openspec-verify-change': '9a8735eaaa34c278d2193eb32fa736f4b111d1c47e675971c8df40f81d20c8c3', 'openspec-onboard': 'b1b6fc9a1b3ff64dafe9b8c39a761ee1bd001b542d47b4e4deaf058e0aa21256', - 'openspec-propose': '0cfc9278123d973929cb4da3ea7ac8ae1b6c84b472eed4fb753657b8347eaeb9', + 'openspec-propose': '024db4bce28d9a4d7b25fa92525da6fc701a64ac07dfdcf777d286c95b5281b5', 'openspec-update-change': '77ff4d1f1cd08a57649cce1f25e0ebc4f55d6d032dfde5c301d1b479561b72fa', };