From 56c72093f3481aca6d4401e42a991fb4e63800f6 Mon Sep 17 00:00:00 2001 From: Clay Good Date: Tue, 21 Jul 2026 08:11:01 -0500 Subject: [PATCH 1/3] fix(templates): make the schema instruction field authoritative for artifact creation The continue-change skill and command embedded hard-coded spec-driven artifact patterns that agents followed instead of the schema's instruction field whenever a custom schema reused familiar artifact names, so schemas could not delegate artifact creation to their own skills. Drop the hard-coded patterns, state that the instruction field is authoritative, and tell both continue and ff workflows to invoke a skill when the instruction delegates to one. Fixes #777 Co-Authored-By: Claude Fable 5 --- .changeset/instruction-field-authority.md | 7 +++++ skills/openspec-continue-change/SKILL.md | 13 ++-------- skills/openspec-ff-change/SKILL.md | 3 ++- .../templates/workflows/continue-change.ts | 26 +++---------------- src/core/templates/workflows/ff-change.ts | 6 +++-- .../templates/skill-templates-parity.test.ts | 6 ++--- 6 files changed, 22 insertions(+), 39 deletions(-) create mode 100644 .changeset/instruction-field-authority.md diff --git a/.changeset/instruction-field-authority.md b/.changeset/instruction-field-authority.md new file mode 100644 index 0000000000..d77ce4d845 --- /dev/null +++ b/.changeset/instruction-field-authority.md @@ -0,0 +1,7 @@ +--- +"@fission-ai/openspec": patch +--- + +### Bug Fixes + +- **Custom schema instructions are no longer overridden by hard-coded spec-driven patterns** — the `openspec-continue-change` skill/command embedded one-line "common artifact patterns" for proposal.md, specs, design.md, and tasks.md, so agents followed those shortcuts instead of the schema's `instruction` field whenever a custom schema reused familiar artifact names. The templates now state that the `instruction` field is the authoritative guidance, and both `continue` and `ff` workflows explicitly direct the agent to invoke a skill when the instruction delegates artifact creation to one (fixes #777). diff --git a/skills/openspec-continue-change/SKILL.md b/skills/openspec-continue-change/SKILL.md index 7a98ceccb1..e8d688515d 100644 --- a/skills/openspec-continue-change/SKILL.md +++ b/skills/openspec-continue-change/SKILL.md @@ -96,18 +96,9 @@ After each invocation, show: **Artifact Creation Guidelines** -The artifact types and their purpose depend on the schema. Use the `instruction` field from the instructions output to understand what to create. +The artifact types and their purpose depend on the schema. The `instruction` field from the instructions output is the authoritative guidance for each artifact - follow it even when the artifact has a familiar name (proposal.md, tasks.md, etc.), since custom schemas may define different content or a different process for the same file names. -Common artifact patterns: - -**spec-driven schema** (proposal → specs → design → tasks): -- **proposal.md**: Ask user about the change if not clear. Fill in Why, What Changes, Capabilities, Impact. - - The Capabilities section is critical - each capability listed will need a spec file. -- **specs//spec.md**: Create one spec per capability listed in the proposal's Capabilities section (use the capability name, not the change name). -- **design.md**: Document technical decisions, architecture, and implementation approach. -- **tasks.md**: Break down implementation into checkboxed tasks. - -For other schemas, follow the `instruction` field from the CLI output. +If the `instruction` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly. **Guardrails** - Create ONE artifact per invocation diff --git a/skills/openspec-ff-change/SKILL.md b/skills/openspec-ff-change/SKILL.md index ad151a7329..15beb5430e 100644 --- a/skills/openspec-ff-change/SKILL.md +++ b/skills/openspec-ff-change/SKILL.md @@ -88,7 +88,8 @@ After completing all artifacts, summarize: **Artifact Creation Guidelines** -- Follow the `instruction` field from `openspec instructions` for each artifact type +- Follow the `instruction` field from `openspec instructions` for each artifact type - it is the authoritative guidance, even for familiar artifact names +- If the `instruction` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly - The schema defines what each artifact should contain - follow it - Read dependency artifacts for context before creating new ones - Use `template` as the structure for your output file - fill in its sections diff --git a/src/core/templates/workflows/continue-change.ts b/src/core/templates/workflows/continue-change.ts index 7af550422c..8fb1ed7e71 100644 --- a/src/core/templates/workflows/continue-change.ts +++ b/src/core/templates/workflows/continue-change.ts @@ -98,18 +98,9 @@ After each invocation, show: **Artifact Creation Guidelines** -The artifact types and their purpose depend on the schema. Use the \`instruction\` field from the instructions output to understand what to create. +The artifact types and their purpose depend on the schema. The \`instruction\` field from the instructions output is the authoritative guidance for each artifact - follow it even when the artifact has a familiar name (proposal.md, tasks.md, etc.), since custom schemas may define different content or a different process for the same file names. -Common artifact patterns: - -**spec-driven schema** (proposal → specs → design → tasks): -- **proposal.md**: Ask user about the change if not clear. Fill in Why, What Changes, Capabilities, Impact. - - The Capabilities section is critical - each capability listed will need a spec file. -- **specs//spec.md**: Create one spec per capability listed in the proposal's Capabilities section (use the capability name, not the change name). -- **design.md**: Document technical decisions, architecture, and implementation approach. -- **tasks.md**: Break down implementation into checkboxed tasks. - -For other schemas, follow the \`instruction\` field from the CLI output. +If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly. **Guardrails** - Create ONE artifact per invocation @@ -220,18 +211,9 @@ After each invocation, show: **Artifact Creation Guidelines** -The artifact types and their purpose depend on the schema. Use the \`instruction\` field from the instructions output to understand what to create. - -Common artifact patterns: - -**spec-driven schema** (proposal → specs → design → tasks): -- **proposal.md**: Ask user about the change if not clear. Fill in Why, What Changes, Capabilities, Impact. - - The Capabilities section is critical - each capability listed will need a spec file. -- **specs//spec.md**: Create one spec per capability listed in the proposal's Capabilities section (use the capability name, not the change name). -- **design.md**: Document technical decisions, architecture, and implementation approach. -- **tasks.md**: Break down implementation into checkboxed tasks. +The artifact types and their purpose depend on the schema. The \`instruction\` field from the instructions output is the authoritative guidance for each artifact - follow it even when the artifact has a familiar name (proposal.md, tasks.md, etc.), since custom schemas may define different content or a different process for the same file names. -For other schemas, follow the \`instruction\` field from the CLI output. +If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly. **Guardrails** - Create ONE artifact per invocation diff --git a/src/core/templates/workflows/ff-change.ts b/src/core/templates/workflows/ff-change.ts index 7f91659721..a3f7057e06 100644 --- a/src/core/templates/workflows/ff-change.ts +++ b/src/core/templates/workflows/ff-change.ts @@ -90,7 +90,8 @@ After completing all artifacts, summarize: **Artifact Creation Guidelines** -- Follow the \`instruction\` field from \`openspec instructions\` for each artifact type +- Follow the \`instruction\` field from \`openspec instructions\` for each artifact type - it is the authoritative guidance, even for familiar artifact names +- If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly - The schema defines what each artifact should contain - follow it - Read dependency artifacts for context before creating new ones - Use \`template\` as the structure for your output file - fill in its sections @@ -195,7 +196,8 @@ After completing all artifacts, summarize: **Artifact Creation Guidelines** -- Follow the \`instruction\` field from \`openspec instructions\` for each artifact type +- Follow the \`instruction\` field from \`openspec instructions\` for each artifact type - it is the authoritative guidance, even for familiar artifact names +- If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly - The schema defines what each artifact should contain - follow it - Read dependency artifacts for context before creating new ones - Use \`template\` as the structure for your output file - fill in its sections diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index aab27767b3..ea553d4e8b 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -39,14 +39,14 @@ import { STORE_SELECTION_GUIDANCE } from '../../../src/core/templates/workflows/ const EXPECTED_FUNCTION_HASHES: Record = { getExploreSkillTemplate: 'a7eb6fabdc05a5b90a4773ba93320a60edffea88e9b27985668a2959dcec2e3d', getNewChangeSkillTemplate: '39663a6d2037e6697020393a66f6327506e3e3bc573b7a3556dcb7f9457dc51d', - getContinueChangeSkillTemplate: 'acc07a489a30192b4bf2bbdc587a889478fbf6fffbbc9353c7775c4ca1ec5011', + getContinueChangeSkillTemplate: 'feff37eb4448e9d4ea8bef4278de20169c9cc3c70a087daeb298a2b96db051e4', getApplyChangeSkillTemplate: '0f5a15fc7fb9ad6059a5643d0e01365d27642637a4aaebf182f9eabb45348197', getFfChangeSkillTemplate: 'e1745de40aaa20170bf9314a5c0de09c22e89b2a33b95d6740305b353d1cc4ff', getSyncSpecsSkillTemplate: '32c3169e1ee0345a174c0bacb8fd16db73477cc006d8cedbedc6077233c5461b', getOnboardSkillTemplate: 'bc2216b72724b01c3a733e63b8bf4aff457f561c0e9ff7288bdacc39780a37a7', getOpsxExploreCommandTemplate: 'eef1f8b4fd90ade6d70be46f0f8c3e6722f221fed175a6f9cf626287ef504a94', getOpsxNewCommandTemplate: '57c600cce318d16b9b4308a18d0d983ea3c0673034e606a7cceec07b4c705e87', - getOpsxContinueCommandTemplate: 'f63964fab7720ede097aa48808baff196c391b962930ca960459205c724800e5', + getOpsxContinueCommandTemplate: '33f58fdfc05498f2579421d560b4175e607edc9dbdebe08a44f0d354e3bf7d33', getOpsxApplyCommandTemplate: 'daeb507206707169de73c828e199648dde5732cbc17791ef2a027adffd028574', getOpsxFfCommandTemplate: '2e187facdbb89d15de09e4fbc926e389e1994bdfa78d0769029c71dff060a006', getArchiveChangeSkillTemplate: 'b04eccde2c57af4bc484fa7279fa873ad1d46474eb024467d68e784d8b985c18', @@ -67,7 +67,7 @@ const EXPECTED_FUNCTION_HASHES: Record = { const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { 'openspec-explore': 'c8de6033b2c78009647647c65a504e4ada1a3bdcee31aed38a4bf7d629513f6e', 'openspec-new-change': 'd5b8909bea70a33b7a312b38ce204a91f40b6bb2bff12c4c06b3e11641b6a689', - 'openspec-continue-change': 'bdb8bbb6a768a741b05256effbc284d65ac6a45360b59c24b94198792d3d0ebf', + 'openspec-continue-change': '3b730703e865f39be9e8715840f1f0f5c0df64e09b9468966980e698f0fe6fbc', 'openspec-apply-change': '09c0e1cdf5ccc82416d0969d6bd715cc70616bdbc3531358a5c36057f78be55a', 'openspec-ff-change': '045487887272576ae6528c6dc90684841ffe86bae7e7a33454531e0e5fc3629b', 'openspec-sync-specs': 'd1bcd420bf8fb55a13f58a2857e6ebde58eb6f9e721a3bf6876bd9f640a63859', From caa27d16cbcdbe9e5547e268cc8326e55dc6b4a5 Mon Sep 17 00:00:00 2001 From: Clay Good Date: Tue, 21 Jul 2026 08:20:04 -0500 Subject: [PATCH 2/3] fix(templates): apply instruction-field delegation at the creation step and in propose Adversarial review findings: the propose workflow shared the same creation loop and pre-fix wording as ff, and the numbered creation steps still commanded a direct write before the agent ever reached the delegation guideline. Add the delegation conditional at the point of creation in propose, continue, and ff (skill and command variants), add the authoritative-instruction bullets to propose, and verify the artifact exists after a delegated skill runs. Co-Authored-By: Claude Fable 5 --- .changeset/instruction-field-authority.md | 2 +- skills/openspec-continue-change/SKILL.md | 3 ++- skills/openspec-ff-change/SKILL.md | 5 +++-- skills/openspec-propose/SKILL.md | 6 ++++-- src/core/templates/workflows/continue-change.ts | 6 ++++-- src/core/templates/workflows/ff-change.ts | 10 ++++++---- src/core/templates/workflows/propose.ts | 12 ++++++++---- test/core/templates/skill-templates-parity.test.ts | 6 +++--- 8 files changed, 31 insertions(+), 19 deletions(-) diff --git a/.changeset/instruction-field-authority.md b/.changeset/instruction-field-authority.md index d77ce4d845..087413289b 100644 --- a/.changeset/instruction-field-authority.md +++ b/.changeset/instruction-field-authority.md @@ -4,4 +4,4 @@ ### Bug Fixes -- **Custom schema instructions are no longer overridden by hard-coded spec-driven patterns** — the `openspec-continue-change` skill/command embedded one-line "common artifact patterns" for proposal.md, specs, design.md, and tasks.md, so agents followed those shortcuts instead of the schema's `instruction` field whenever a custom schema reused familiar artifact names. The templates now state that the `instruction` field is the authoritative guidance, and both `continue` and `ff` workflows explicitly direct the agent to invoke a skill when the instruction delegates artifact creation to one (fixes #777). +- **Custom schema instructions are no longer overridden by hard-coded spec-driven patterns** — the `openspec-continue-change` skill/command embedded one-line "common artifact patterns" for proposal.md, specs, design.md, and tasks.md, so agents followed those shortcuts instead of the schema's `instruction` field whenever a custom schema reused familiar artifact names. The templates now state that the `instruction` field is the authoritative guidance, and the `propose`, `continue`, and `ff` workflows direct the agent — both in the artifact-creation step and in the guidelines — to invoke a skill when the instruction delegates artifact creation to one, verifying the artifact exists afterward (fixes #777). diff --git a/skills/openspec-continue-change/SKILL.md b/skills/openspec-continue-change/SKILL.md index e8d688515d..0e6cdd12af 100644 --- a/skills/openspec-continue-change/SKILL.md +++ b/skills/openspec-continue-change/SKILL.md @@ -67,6 +67,7 @@ Continue working on a change by creating the next artifact. - `resolvedOutputPath`: Resolved path or pattern to write the artifact - `dependencies`: Completed artifacts to read for context - **Create the artifact file**: + - If the `instruction` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of following the bullets below, then verify the artifact file exists at `resolvedOutputPath` - 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 @@ -98,7 +99,7 @@ After each invocation, show: The artifact types and their purpose depend on the schema. The `instruction` field from the instructions output is the authoritative guidance for each artifact - follow it even when the artifact has a familiar name (proposal.md, tasks.md, etc.), since custom schemas may define different content or a different process for the same file names. -If the `instruction` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly. +If the `instruction` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly. **Guardrails** - Create ONE artifact per invocation diff --git a/skills/openspec-ff-change/SKILL.md b/skills/openspec-ff-change/SKILL.md index 15beb5430e..a27bc5ab39 100644 --- a/skills/openspec-ff-change/SKILL.md +++ b/skills/openspec-ff-change/SKILL.md @@ -60,7 +60,8 @@ Fast-forward through artifact creation - generate everything needed to start imp - `resolvedOutputPath`: Resolved path or pattern to write the artifact - `dependencies`: Completed artifacts to read 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` + - If the `instruction` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at `resolvedOutputPath` + - Otherwise 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 " @@ -89,7 +90,7 @@ After completing all artifacts, summarize: **Artifact Creation Guidelines** - Follow the `instruction` field from `openspec instructions` for each artifact type - it is the authoritative guidance, even for familiar artifact names -- If the `instruction` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly +- If the `instruction` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly - The schema defines what each artifact should contain - follow it - Read dependency artifacts for context before creating new ones - Use `template` as the structure for your output file - fill in its sections diff --git a/skills/openspec-propose/SKILL.md b/skills/openspec-propose/SKILL.md index 31c4aba3de..76446528fd 100644 --- a/skills/openspec-propose/SKILL.md +++ b/skills/openspec-propose/SKILL.md @@ -69,7 +69,8 @@ When ready to implement, run /openspec-apply-change - `resolvedOutputPath`: Resolved path or pattern to write the artifact - `dependencies`: Completed artifacts to read 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` + - If the `instruction` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at `resolvedOutputPath` + - Otherwise 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 " @@ -97,7 +98,8 @@ After completing all artifacts, summarize: **Artifact Creation Guidelines** -- Follow the `instruction` field from `openspec instructions` for each artifact type +- Follow the `instruction` field from `openspec instructions` for each artifact type - it is the authoritative guidance, even for familiar artifact names +- If the `instruction` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly - The schema defines what each artifact should contain - follow it - Read dependency artifacts for context before creating new ones - Use `template` as the structure for your output file - fill in its sections diff --git a/src/core/templates/workflows/continue-change.ts b/src/core/templates/workflows/continue-change.ts index 8fb1ed7e71..1d98014517 100644 --- a/src/core/templates/workflows/continue-change.ts +++ b/src/core/templates/workflows/continue-change.ts @@ -69,6 +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**: + - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of following the bullets below, then verify the artifact file exists at \`resolvedOutputPath\` - 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 @@ -100,7 +101,7 @@ After each invocation, show: The artifact types and their purpose depend on the schema. The \`instruction\` field from the instructions output is the authoritative guidance for each artifact - follow it even when the artifact has a familiar name (proposal.md, tasks.md, etc.), since custom schemas may define different content or a different process for the same file names. -If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly. +If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly. **Guardrails** - Create ONE artifact per invocation @@ -182,6 +183,7 @@ ${STORE_SELECTION_GUIDANCE} - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read for context - **Create the artifact file**: + - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of following the bullets below, then verify the artifact file exists at \`resolvedOutputPath\` - 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 @@ -213,7 +215,7 @@ After each invocation, show: The artifact types and their purpose depend on the schema. The \`instruction\` field from the instructions output is the authoritative guidance for each artifact - follow it even when the artifact has a familiar name (proposal.md, tasks.md, etc.), since custom schemas may define different content or a different process for the same file names. -If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly. +If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly. **Guardrails** - Create ONE artifact per invocation diff --git a/src/core/templates/workflows/ff-change.ts b/src/core/templates/workflows/ff-change.ts index a3f7057e06..b4e85e3ea7 100644 --- a/src/core/templates/workflows/ff-change.ts +++ b/src/core/templates/workflows/ff-change.ts @@ -62,7 +62,8 @@ ${STORE_SELECTION_GUIDANCE} - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read 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\` + - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at \`resolvedOutputPath\` + - Otherwise 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 " @@ -91,7 +92,7 @@ After completing all artifacts, summarize: **Artifact Creation Guidelines** - Follow the \`instruction\` field from \`openspec instructions\` for each artifact type - it is the authoritative guidance, even for familiar artifact names -- If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly +- If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly - The schema defines what each artifact should contain - follow it - Read dependency artifacts for context before creating new ones - Use \`template\` as the structure for your output file - fill in its sections @@ -168,7 +169,8 @@ ${STORE_SELECTION_GUIDANCE} - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read 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\` + - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at \`resolvedOutputPath\` + - Otherwise 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 " @@ -197,7 +199,7 @@ After completing all artifacts, summarize: **Artifact Creation Guidelines** - Follow the \`instruction\` field from \`openspec instructions\` for each artifact type - it is the authoritative guidance, even for familiar artifact names -- If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke that skill instead of writing the artifact directly +- If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly - The schema defines what each artifact should contain - follow it - Read dependency artifacts for context before creating new ones - Use \`template\` as the structure for your output file - fill in its sections diff --git a/src/core/templates/workflows/propose.ts b/src/core/templates/workflows/propose.ts index d166d7e708..edcf2c582d 100644 --- a/src/core/templates/workflows/propose.ts +++ b/src/core/templates/workflows/propose.ts @@ -71,7 +71,8 @@ ${STORE_SELECTION_GUIDANCE} - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read 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\` + - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at \`resolvedOutputPath\` + - Otherwise 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 " @@ -99,7 +100,8 @@ After completing all artifacts, summarize: **Artifact Creation Guidelines** -- Follow the \`instruction\` field from \`openspec instructions\` for each artifact type +- Follow the \`instruction\` field from \`openspec instructions\` for each artifact type - it is the authoritative guidance, even for familiar artifact names +- If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly - The schema defines what each artifact should contain - follow it - Read dependency artifacts for context before creating new ones - Use \`template\` as the structure for your output file - fill in its sections @@ -185,7 +187,8 @@ ${STORE_SELECTION_GUIDANCE} - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read 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\` + - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at \`resolvedOutputPath\` + - Otherwise 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 " @@ -213,7 +216,8 @@ After completing all artifacts, summarize: **Artifact Creation Guidelines** -- Follow the \`instruction\` field from \`openspec instructions\` for each artifact type +- Follow the \`instruction\` field from \`openspec instructions\` for each artifact type - it is the authoritative guidance, even for familiar artifact names +- If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly - The schema defines what each artifact should contain - follow it - Read dependency artifacts for context before creating new ones - Use \`template\` as the structure for your output file - fill in its sections diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index ea553d4e8b..23d5cf0f93 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -39,14 +39,14 @@ import { STORE_SELECTION_GUIDANCE } from '../../../src/core/templates/workflows/ const EXPECTED_FUNCTION_HASHES: Record = { getExploreSkillTemplate: 'a7eb6fabdc05a5b90a4773ba93320a60edffea88e9b27985668a2959dcec2e3d', getNewChangeSkillTemplate: '39663a6d2037e6697020393a66f6327506e3e3bc573b7a3556dcb7f9457dc51d', - getContinueChangeSkillTemplate: 'feff37eb4448e9d4ea8bef4278de20169c9cc3c70a087daeb298a2b96db051e4', + getContinueChangeSkillTemplate: 'd9f8e184577445fccf9947ece3e2c1a49381075760a1f2069472696423bd35b0', getApplyChangeSkillTemplate: '0f5a15fc7fb9ad6059a5643d0e01365d27642637a4aaebf182f9eabb45348197', getFfChangeSkillTemplate: 'e1745de40aaa20170bf9314a5c0de09c22e89b2a33b95d6740305b353d1cc4ff', getSyncSpecsSkillTemplate: '32c3169e1ee0345a174c0bacb8fd16db73477cc006d8cedbedc6077233c5461b', getOnboardSkillTemplate: 'bc2216b72724b01c3a733e63b8bf4aff457f561c0e9ff7288bdacc39780a37a7', getOpsxExploreCommandTemplate: 'eef1f8b4fd90ade6d70be46f0f8c3e6722f221fed175a6f9cf626287ef504a94', getOpsxNewCommandTemplate: '57c600cce318d16b9b4308a18d0d983ea3c0673034e606a7cceec07b4c705e87', - getOpsxContinueCommandTemplate: '33f58fdfc05498f2579421d560b4175e607edc9dbdebe08a44f0d354e3bf7d33', + getOpsxContinueCommandTemplate: 'f627fb0d8a0d285d83f5c50e28effc503ffea7f1a74347528357c41f7bb7bb1b', getOpsxApplyCommandTemplate: 'daeb507206707169de73c828e199648dde5732cbc17791ef2a027adffd028574', getOpsxFfCommandTemplate: '2e187facdbb89d15de09e4fbc926e389e1994bdfa78d0769029c71dff060a006', getArchiveChangeSkillTemplate: 'b04eccde2c57af4bc484fa7279fa873ad1d46474eb024467d68e784d8b985c18', @@ -67,7 +67,7 @@ const EXPECTED_FUNCTION_HASHES: Record = { const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { 'openspec-explore': 'c8de6033b2c78009647647c65a504e4ada1a3bdcee31aed38a4bf7d629513f6e', 'openspec-new-change': 'd5b8909bea70a33b7a312b38ce204a91f40b6bb2bff12c4c06b3e11641b6a689', - 'openspec-continue-change': '3b730703e865f39be9e8715840f1f0f5c0df64e09b9468966980e698f0fe6fbc', + 'openspec-continue-change': 'a2b721956ec86ed56a7defc7a692453246a5e9bac79159adc9b2694847245297', 'openspec-apply-change': '09c0e1cdf5ccc82416d0969d6bd715cc70616bdbc3531358a5c36057f78be55a', 'openspec-ff-change': '045487887272576ae6528c6dc90684841ffe86bae7e7a33454531e0e5fc3629b', 'openspec-sync-specs': 'd1bcd420bf8fb55a13f58a2857e6ebde58eb6f9e721a3bf6876bd9f640a63859', From 78759e129216a448e80e5b56fd560aadc60d22e5 Mon Sep 17 00:00:00 2001 From: Clay Good Date: Tue, 21 Jul 2026 09:03:52 -0500 Subject: [PATCH 3/3] fix(templates): read dependencies before delegating, pin #777 behavior in tests Address alfred's review: the hash baselines alone accepted any regenerated prompt, so add a focused parity assertion covering all six variants (propose/continue/ff x skill/command) that the instruction field is the authoritative guidance, delegated creation is invoked and verified at the creation step and restated in the guidelines, and the old "Common artifact patterns" shortcut stays gone. The test fails against the pre-fix templates. Also fix an ordering contradiction the adversarial review surfaced: the continue-change delegation bullet preceded the dependency-read bullet and said "instead of following the bullets below", telling agents to skip dependency reads that the guardrails require. It now mirrors propose/ff: read dependencies first, then delegate "instead of writing the file yourself" - making the sentence identical across all six variants. Co-Authored-By: Claude Fable 5 --- skills/openspec-continue-change/SKILL.md | 4 +- .../templates/workflows/continue-change.ts | 8 ++-- .../templates/skill-templates-parity.test.ts | 48 +++++++++++++++---- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/skills/openspec-continue-change/SKILL.md b/skills/openspec-continue-change/SKILL.md index 0e6cdd12af..cbce137c0c 100644 --- a/skills/openspec-continue-change/SKILL.md +++ b/skills/openspec-continue-change/SKILL.md @@ -67,9 +67,9 @@ Continue working on a change by creating the next artifact. - `resolvedOutputPath`: Resolved path or pattern to write the artifact - `dependencies`: Completed artifacts to read for context - **Create the artifact file**: - - If the `instruction` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of following the bullets below, then verify the artifact file exists at `resolvedOutputPath` - 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 + - If the `instruction` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at `resolvedOutputPath` + - Otherwise 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 - Show what was created and what's now unlocked diff --git a/src/core/templates/workflows/continue-change.ts b/src/core/templates/workflows/continue-change.ts index 1d98014517..8c5d8b4ace 100644 --- a/src/core/templates/workflows/continue-change.ts +++ b/src/core/templates/workflows/continue-change.ts @@ -69,9 +69,9 @@ ${STORE_SELECTION_GUIDANCE} - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read for context - **Create the artifact file**: - - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of following the bullets below, then verify the artifact file exists at \`resolvedOutputPath\` - 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 + - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at \`resolvedOutputPath\` + - Otherwise 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 - Show what was created and what's now unlocked @@ -183,9 +183,9 @@ ${STORE_SELECTION_GUIDANCE} - \`resolvedOutputPath\`: Resolved path or pattern to write the artifact - \`dependencies\`: Completed artifacts to read for context - **Create the artifact file**: - - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of following the bullets below, then verify the artifact file exists at \`resolvedOutputPath\` - 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 + - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at \`resolvedOutputPath\` + - Otherwise 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 - Show what was created and what's now unlocked diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index 23d5cf0f93..1a106dfceb 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: 'a7eb6fabdc05a5b90a4773ba93320a60edffea88e9b27985668a2959dcec2e3d', getNewChangeSkillTemplate: '39663a6d2037e6697020393a66f6327506e3e3bc573b7a3556dcb7f9457dc51d', - getContinueChangeSkillTemplate: 'd9f8e184577445fccf9947ece3e2c1a49381075760a1f2069472696423bd35b0', + getContinueChangeSkillTemplate: '912ce98855bcea351a73730c7ac18505e21512266eac8082351ef72ddfa63906', getApplyChangeSkillTemplate: '0f5a15fc7fb9ad6059a5643d0e01365d27642637a4aaebf182f9eabb45348197', - getFfChangeSkillTemplate: 'e1745de40aaa20170bf9314a5c0de09c22e89b2a33b95d6740305b353d1cc4ff', + getFfChangeSkillTemplate: '25b584cdda0b99c704dbe473b0dfae084af2fac6f4ca27fe7422fb8789b0fe16', getSyncSpecsSkillTemplate: '32c3169e1ee0345a174c0bacb8fd16db73477cc006d8cedbedc6077233c5461b', getOnboardSkillTemplate: 'bc2216b72724b01c3a733e63b8bf4aff457f561c0e9ff7288bdacc39780a37a7', getOpsxExploreCommandTemplate: 'eef1f8b4fd90ade6d70be46f0f8c3e6722f221fed175a6f9cf626287ef504a94', getOpsxNewCommandTemplate: '57c600cce318d16b9b4308a18d0d983ea3c0673034e606a7cceec07b4c705e87', - getOpsxContinueCommandTemplate: 'f627fb0d8a0d285d83f5c50e28effc503ffea7f1a74347528357c41f7bb7bb1b', + getOpsxContinueCommandTemplate: '7843e40ad80611a80bcd3c8c5abd5ce7f89efe72f749a482fd1d0594762e94f3', getOpsxApplyCommandTemplate: 'daeb507206707169de73c828e199648dde5732cbc17791ef2a027adffd028574', - getOpsxFfCommandTemplate: '2e187facdbb89d15de09e4fbc926e389e1994bdfa78d0769029c71dff060a006', + getOpsxFfCommandTemplate: 'd2d8ea4f6ebf68fb591ce45796aa62387c6c40030360963fae0589fb003c559f', getArchiveChangeSkillTemplate: 'b04eccde2c57af4bc484fa7279fa873ad1d46474eb024467d68e784d8b985c18', getBulkArchiveChangeSkillTemplate: '2b74b1f73380ff32e35f580734780d843c6161a2748c39edb07f1e00453771b4', getOpsxSyncCommandTemplate: '68dc44c9be2ec1ef719a4ed59830e5a0bc74c3ba6113070650266e1b0d153071', @@ -57,8 +57,8 @@ const EXPECTED_FUNCTION_HASHES: Record = { getOpsxOnboardCommandTemplate: '9430a0fb6530791ab720e068f4b172bc3dfc4e96a1ae29102bee0b92c2afe7b5', getOpsxBulkArchiveCommandTemplate: 'da7be1a7318f15b915f5aae8eb638797a8a24a31e5fc7fc0a2bad01bba137686', getOpsxVerifyCommandTemplate: 'f01c0c0cef53be0956de52363d955d4ace131b1b2d77adf902f35fead9a1486d', - getOpsxProposeSkillTemplate: '9c17bbe73ee7bcd95bfdb6f2bbb6a2deda2be0f870904fc740018b8b017530c0', - getOpsxProposeCommandTemplate: 'b47d1b254d715b454cc64aa146fe994e8c0775352a7c7043d8818b05ec77d53c', + getOpsxProposeSkillTemplate: '1cb094f058e884aa8ddacd2ea756e4985bfb56b60628ca680e00cc0bdb97101d', + getOpsxProposeCommandTemplate: '494cfbe3a10510d356b513969481541088108123107562a6d4e2f0592ab9db34', getFeedbackSkillTemplate: 'd7d83c5f7fc2b92fe8f4588a5bf2d9cb315e4c73ec19bcd5ef28270906319a0d', getUpdateChangeSkillTemplate: 'fe2e8edaf973d42dc7fc7dfd846105c4c3cfec0437606e582ec644985cd4e81d', getOpsxUpdateCommandTemplate: 'e55ac5774203a7d9037d2d588889c97c53f3f930da49497cc79e865375920da7', @@ -67,15 +67,15 @@ const EXPECTED_FUNCTION_HASHES: Record = { const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { 'openspec-explore': 'c8de6033b2c78009647647c65a504e4ada1a3bdcee31aed38a4bf7d629513f6e', 'openspec-new-change': 'd5b8909bea70a33b7a312b38ce204a91f40b6bb2bff12c4c06b3e11641b6a689', - 'openspec-continue-change': 'a2b721956ec86ed56a7defc7a692453246a5e9bac79159adc9b2694847245297', + 'openspec-continue-change': '30b074eec5f1e70bba3a71d50175dbbcb2994a64930cb4cfd1660872ba767018', 'openspec-apply-change': '09c0e1cdf5ccc82416d0969d6bd715cc70616bdbc3531358a5c36057f78be55a', - 'openspec-ff-change': '045487887272576ae6528c6dc90684841ffe86bae7e7a33454531e0e5fc3629b', + 'openspec-ff-change': 'fa41b10a3101ba58742f9c15fe35f843c1ebcb94c7e4898bd7feaadd6676a80c', 'openspec-sync-specs': 'd1bcd420bf8fb55a13f58a2857e6ebde58eb6f9e721a3bf6876bd9f640a63859', 'openspec-archive-change': 'b24d326662ef58809de4464960440713748b9a281323357facdca24af52014e7', 'openspec-bulk-archive-change': '49d410bda408c0411decd584be9c2355335e3b3db760fc6a0adcd82c172a280f', 'openspec-verify-change': '57693d22940f06080c6cf8d590ac2f48240d4a5e9ce7074dacd0f8d3c9945afa', 'openspec-onboard': '76225d10352454a304e56566997811d16f91de1b37653816f2bc5d8ec976febc', - 'openspec-propose': 'fe3996b4f7355da28187680c978de8ba0b794702192ce2bdaa8abe09d810270d', + 'openspec-propose': '69329d1eaacfff230d8641809e0290c8b501055ce301a8b76d4c044f42e1fec2', 'openspec-update-change': '77ff4d1f1cd08a57649cce1f25e0ebc4f55d6d032dfde5c301d1b479561b72fa', }; @@ -312,4 +312,34 @@ describe('skill templates split parity', () => { ); } }); + + it('makes the schema instruction field authoritative for artifact creation (#777)', () => { + const variants: Array<[string, string]> = [ + ['propose skill', generateSkillContent(getOpsxProposeSkillTemplate(), 'PARITY-BASELINE')], + ['propose command', getOpsxProposeCommandTemplate().content], + ['continue skill', generateSkillContent(getContinueChangeSkillTemplate(), 'PARITY-BASELINE')], + ['continue command', getOpsxContinueCommandTemplate().content], + ['ff skill', generateSkillContent(getFfChangeSkillTemplate(), 'PARITY-BASELINE')], + ['ff command', getOpsxFfCommandTemplate().content], + ]; + + for (const [variant, content] of variants) { + // The instruction field wins even for familiar artifact names: the old + // hard-coded "Common artifact patterns" shortcut is what let agents + // ignore custom schemas that reuse proposal.md/tasks.md file names. + expect(content, variant).toContain('the authoritative guidance'); + expect(content, variant).not.toContain('Common artifact patterns'); + + // Delegated creation is honored at the creation step itself, and the + // delegated skill's output is verified rather than assumed. + expect(content, variant).toContain( + 'If the `instruction` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at `resolvedOutputPath`' + ); + + // ...and restated in the artifact-creation guidelines. + expect(content, variant).toContain( + 'If the `instruction` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly' + ); + } + }); });