From 56b54285b7b13359d410d043ced868f7b54399ce Mon Sep 17 00:00:00 2001 From: shashank dwivedi Date: Tue, 2 Jun 2026 01:43:57 +0530 Subject: [PATCH 1/6] fix(templates): deduplicate apply skill and command instructions Extract shared APPLY_INSTRUCTIONS constant so skill and command templates reference the same string. Eliminates content drift reported in #1139. --- src/core/templates/workflows/apply-change.ts | 176 ++----------------- 1 file changed, 18 insertions(+), 158 deletions(-) diff --git a/src/core/templates/workflows/apply-change.ts b/src/core/templates/workflows/apply-change.ts index ec5b59ab16..12752c437b 100644 --- a/src/core/templates/workflows/apply-change.ts +++ b/src/core/templates/workflows/apply-change.ts @@ -6,13 +6,14 @@ */ import type { SkillTemplate, CommandTemplate } from '../types.js'; -export function getApplyChangeSkillTemplate(): SkillTemplate { - return { - name: 'openspec-apply-change', - description: 'Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.', - instructions: `Implement tasks from an OpenSpec change. +// ── Shared instruction body ─────────────────────────────────────────────────── +// Single source of truth for apply workflow instructions. +// Both the skill template and command template reference this constant, +// eliminating content drift between the two generated files. +// See: https://github.com/Fission-AI/OpenSpec/issues/1139 +const APPLY_INSTRUCTIONS = `Implement tasks from an OpenSpec change. -**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes. +**Input**: Optionally specify a change name (e.g., \`/opsx:apply add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes. **Steps** @@ -47,7 +48,7 @@ export function getApplyChangeSkillTemplate(): SkillTemplate { - Dynamic instruction based on current state **Handle states:** - - If \`state: "blocked"\` (missing artifacts): show message, suggest using openspec-continue-change + - If \`state: "blocked"\` (missing artifacts): show message, suggest using \`/opsx:continue\` - If \`state: "all_done"\`: congratulate, suggest archive - Otherwise: proceed to implementation @@ -119,7 +120,7 @@ Working on task 4/7: - [x] Task 2 ... -All tasks complete! Ready to archive this change. +All tasks complete! You can archive this change with \`/opsx:archive\`. \`\`\` **Output On Pause (Issue Encountered)** @@ -157,7 +158,13 @@ What would you like to do? This skill supports the "actions on a change" model: - **Can be invoked anytime**: Before all artifacts are done (if tasks exist), after partial implementation, interleaved with other actions -- **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly`, +- **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly`; + +export function getApplyChangeSkillTemplate(): SkillTemplate { + return { + name: 'openspec-apply-change', + description: 'Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.', + instructions: APPLY_INSTRUCTIONS, license: 'MIT', compatibility: 'Requires openspec CLI.', metadata: { author: 'openspec', version: '1.0' }, @@ -170,153 +177,6 @@ export function getOpsxApplyCommandTemplate(): CommandTemplate { description: 'Implement tasks from an OpenSpec change (Experimental)', category: 'Workflow', tags: ['workflow', 'artifacts', 'experimental'], - content: `Implement tasks from an OpenSpec change. - -**Input**: Optionally specify a change name (e.g., \`/opsx:apply add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes. - -**Steps** - -1. **Select the change** - - If a name is provided, use it. Otherwise: - - Infer from conversation context if the user mentioned a change - - Auto-select if only one active change exists - - If ambiguous, run \`openspec list --json\` to get available changes and use the **AskUserQuestion tool** to let the user select - - Always announce: "Using change: " and how to override (e.g., \`/opsx:apply \`). - -2. **Check status to understand the schema** - \`\`\`bash - openspec status --change "" --json - \`\`\` - Parse the JSON to understand: - - \`schemaName\`: The workflow being used (e.g., "spec-driven") - - \`planningHome\`, \`changeRoot\`, and \`actionContext\`: planning scope and edit constraints - - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) - -3. **Get apply instructions** - - \`\`\`bash - openspec instructions apply --change "" --json - \`\`\` - - This returns: - - \`contextFiles\`: artifact ID -> array of concrete file paths (varies by schema) - - Progress (total, complete, remaining) - - Task list with status - - Dynamic instruction based on current state - - **Handle states:** - - If \`state: "blocked"\` (missing artifacts): show message, suggest using \`/opsx:continue\` - - If \`state: "all_done"\`: congratulate, suggest archive - - Otherwise: proceed to implementation - - **Workspace guard:** If status JSON reports \`actionContext.mode: "workspace-planning"\` and \`allowedEditRoots\` is empty, explain that full workspace apply is not supported in this slice. Treat linked repos and folders as read-only context, ask the user to select an affected area through an explicit implementation workflow, and STOP before editing files. - -4. **Read context files** - - Read every file path listed under \`contextFiles\` from the apply instructions output. - The files depend on the schema being used: - - **spec-driven**: proposal, specs, design, tasks - - Other schemas: follow the contextFiles from CLI output - -5. **Show current progress** - - Display: - - Schema being used - - Progress: "N/M tasks complete" - - Remaining tasks overview - - Dynamic instruction from CLI - -6. **Implement tasks (loop until done or blocked)** - - For each pending task: - - Show which task is being worked on - - Make the code changes required - - Keep changes minimal and focused - - Mark task complete in the tasks file: \`- [ ]\` → \`- [x]\` - - Continue to next task - - **Pause if:** - - Task is unclear → ask for clarification - - Implementation reveals a design issue → suggest updating artifacts - - Error or blocker encountered → report and wait for guidance - - User interrupts - -7. **On completion or pause, show status** - - Display: - - Tasks completed this session - - Overall progress: "N/M tasks complete" - - If all done: suggest archive - - If paused: explain why and wait for guidance - -**Output During Implementation** - -\`\`\` -## Implementing: (schema: ) - -Working on task 3/7: -[...implementation happening...] -✓ Task complete - -Working on task 4/7: -[...implementation happening...] -✓ Task complete -\`\`\` - -**Output On Completion** - -\`\`\` -## Implementation Complete - -**Change:** -**Schema:** -**Progress:** 7/7 tasks complete ✓ - -### Completed This Session -- [x] Task 1 -- [x] Task 2 -... - -All tasks complete! You can archive this change with \`/opsx:archive\`. -\`\`\` - -**Output On Pause (Issue Encountered)** - -\`\`\` -## Implementation Paused - -**Change:** -**Schema:** -**Progress:** 4/7 tasks complete - -### Issue Encountered - - -**Options:** -1.