Merge branch 'main' into TabishB/west-monroe

This commit is contained in:
Tabish Bidiwale
2026-01-05 17:12:18 -08:00
committed by GitHub
2 changed files with 378 additions and 12 deletions
+57 -12
View File
@@ -26,7 +26,7 @@ import {
type ArtifactInstructions,
} from '../core/artifact-graph/index.js';
import { createChange, validateChangeName } from '../utils/change-utils.js';
import { getNewChangeSkillTemplate, getContinueChangeSkillTemplate, getApplyChangeSkillTemplate } from '../core/templates/skill-templates.js';
import { getNewChangeSkillTemplate, getContinueChangeSkillTemplate, getApplyChangeSkillTemplate, getOpsxNewCommandTemplate, getOpsxContinueCommandTemplate, getOpsxApplyCommandTemplate } from '../core/templates/skill-templates.js';
import { FileSystemUtils } from '../utils/file-system.js';
// -----------------------------------------------------------------------------
@@ -701,21 +701,28 @@ async function newChangeCommand(name: string | undefined, options: NewChangeOpti
// -----------------------------------------------------------------------------
/**
* Generates Agent Skills for the experimental artifact workflow.
* Generates Agent Skills and slash commands for the experimental artifact workflow.
* Creates .claude/skills/ directory with SKILL.md files following Agent Skills spec.
* Creates .claude/commands/opsx/ directory with slash command files.
*/
async function artifactExperimentalSetupCommand(): Promise<void> {
const spinner = ora('Setting up experimental artifact workflow skills...').start();
const spinner = ora('Setting up experimental artifact workflow...').start();
try {
const projectRoot = process.cwd();
const skillsDir = path.join(projectRoot, '.claude', 'skills');
const commandsDir = path.join(projectRoot, '.claude', 'commands', 'opsx');
// Get skill templates
const newChangeSkill = getNewChangeSkillTemplate();
const continueChangeSkill = getContinueChangeSkillTemplate();
const applyChangeSkill = getApplyChangeSkillTemplate();
// Get command templates
const newCommand = getOpsxNewCommandTemplate();
const continueCommand = getOpsxContinueCommandTemplate();
const applyCommand = getOpsxApplyCommandTemplate();
// Create skill directories and SKILL.md files
const skills = [
{ template: newChangeSkill, dirName: 'openspec-new-change' },
@@ -723,7 +730,7 @@ async function artifactExperimentalSetupCommand(): Promise<void> {
{ template: applyChangeSkill, dirName: 'openspec-apply-change' },
];
const createdFiles: string[] = [];
const createdSkillFiles: string[] = [];
for (const { template, dirName } of skills) {
const skillDir = path.join(skillsDir, dirName);
@@ -740,31 +747,69 @@ ${template.instructions}
// Write the skill file
await FileSystemUtils.writeFile(skillFile, skillContent);
createdFiles.push(path.relative(projectRoot, skillFile));
createdSkillFiles.push(path.relative(projectRoot, skillFile));
}
// Create slash command files
const commands = [
{ template: newCommand, fileName: 'new.md' },
{ template: continueCommand, fileName: 'continue.md' },
{ template: applyCommand, fileName: 'apply.md' },
];
const createdCommandFiles: string[] = [];
for (const { template, fileName } of commands) {
const commandFile = path.join(commandsDir, fileName);
// Generate command content with YAML frontmatter
const commandContent = `---
name: ${template.name}
description: ${template.description}
category: ${template.category}
tags: [${template.tags.join(', ')}]
---
${template.content}
`;
// Write the command file
await FileSystemUtils.writeFile(commandFile, commandContent);
createdCommandFiles.push(path.relative(projectRoot, commandFile));
}
spinner.succeed('Experimental artifact workflow setup complete!');
// Print success message
console.log();
console.log(chalk.bold('🧪 Experimental Artifact Workflow Skills Created'));
console.log(chalk.bold('🧪 Experimental Artifact Workflow Setup Complete'));
console.log();
for (const file of createdFiles) {
console.log(chalk.bold('Skills Created:'));
for (const file of createdSkillFiles) {
console.log(chalk.green(' ✓ ' + file));
}
console.log();
console.log(chalk.bold('Slash Commands Created:'));
for (const file of createdCommandFiles) {
console.log(chalk.green(' ✓ ' + file));
}
console.log();
console.log(chalk.bold('📖 Usage:'));
console.log();
console.log(' Skills work automatically in compatible editors:');
console.log(' • ' + chalk.cyan('Claude Code') + ' - Auto-detected, ready to use');
console.log(' • ' + chalk.cyan('Cursor') + ' - Enable in Settings → Rules → Import Settings');
console.log(' • ' + chalk.cyan('Windsurf') + ' - Auto-imports from .claude directory');
console.log(' ' + chalk.cyan('Skills') + ' work automatically in compatible editors:');
console.log(' • Claude Code - Auto-detected, ready to use');
console.log(' • Cursor - Enable in Settings → Rules → Import Settings');
console.log(' • Windsurf - Auto-imports from .claude directory');
console.log();
console.log(' Ask Claude naturally:');
console.log(' • "I want to start a new OpenSpec change to add <feature>"');
console.log(' • "Continue working on this change"');
console.log(' • "Implement the tasks for this change"');
console.log();
console.log(' Claude will automatically use the appropriate skill.');
console.log(' ' + chalk.cyan('Slash Commands') + ' for explicit invocation:');
console.log(' • /opsx:new - Start a new change');
console.log(' • /opsx:continue - Create the next artifact');
console.log(' • /opsx:apply - Implement tasks');
console.log();
console.log(chalk.yellow('💡 This is an experimental feature.'));
console.log(' Feedback welcome at: https://github.com/Fission-AI/OpenSpec/issues');
+321
View File
@@ -319,3 +319,324 @@ This skill supports the "actions on a change" model:
- **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly`
};
}
// -----------------------------------------------------------------------------
// Slash Command Templates
// -----------------------------------------------------------------------------
export interface CommandTemplate {
name: string;
description: string;
category: string;
tags: string[];
content: string;
}
/**
* Template for /opsx:new slash command
*/
export function getOpsxNewCommandTemplate(): CommandTemplate {
return {
name: 'OPSX: New',
description: 'Start a new change using the experimental artifact workflow (OPSX)',
category: 'Workflow',
tags: ['workflow', 'artifacts', 'experimental'],
content: `Start a new change using the experimental artifact-driven approach.
**Input**: The argument after \`/opsx:new\` is the change name (kebab-case), OR a description of what the user wants to build.
**Steps**
1. **If no input provided, ask what they want to build**
Use the **AskUserQuestion tool** (open-ended, no preset options) to ask:
> "What change do you want to work on? Describe what you want to build or fix."
From their description, derive a kebab-case name (e.g., "add user authentication" → \`add-user-auth\`).
**IMPORTANT**: Do NOT proceed without understanding what the user wants to build.
2. **Create the change directory**
\`\`\`bash
openspec new change "<name>"
\`\`\`
This creates a scaffolded change at \`openspec/changes/<name>/\`.
3. **Show the artifact status**
\`\`\`bash
openspec status --change "<name>"
\`\`\`
This shows which artifacts need to be created and which are ready (dependencies satisfied).
4. **Get instructions for the first artifact**
The first artifact is always \`proposal\` (no dependencies).
\`\`\`bash
openspec instructions proposal --change "<name>"
\`\`\`
This outputs the template and context for creating the proposal.
5. **STOP and wait for user direction**
**Output**
After completing the steps, summarize:
- Change name and location
- Current status (0/4 artifacts complete)
- The template for the proposal artifact
- Prompt: "Ready to create the proposal? Run \`/opsx:continue\` or just describe what this change is about and I'll draft the proposal."
**Guardrails**
- Do NOT create any artifacts yet - just show the instructions
- Do NOT advance beyond showing the proposal template
- If the name is invalid (not kebab-case), ask for a valid name
- If a change with that name already exists, suggest using \`/opsx:continue\` instead`
};
}
/**
* Template for /opsx:continue slash command
*/
export function getOpsxContinueCommandTemplate(): CommandTemplate {
return {
name: 'OPSX: Continue',
description: 'Continue working on a change - create the next artifact (Experimental)',
category: 'Workflow',
tags: ['workflow', 'artifacts', 'experimental'],
content: `Continue working on a change by creating the next artifact.
**Input**: Optionally specify \`--change <name>\` after \`/opsx:continue\`. If omitted, MUST prompt for available changes.
**Steps**
1. **If no change name provided, prompt for selection**
Run \`openspec list --json\` to get available changes sorted by most recently modified. Then use the **AskUserQuestion tool** to let the user select which change to work on.
Present the top 3-4 most recently modified changes as options, showing:
- Change name
- Status (e.g., "0/5 tasks", "complete", "no tasks")
- How recently it was modified (from \`lastModified\` field)
Mark the most recently modified change as "(Recommended)" since it's likely what the user wants to continue.
**IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
2. **Check current status**
\`\`\`bash
openspec status --change "<name>" --json
\`\`\`
Parse the JSON to understand current state.
3. **Act based on status**:
---
**If all artifacts are complete (\`isComplete: true\`)**:
- Congratulate the user
- Show final status
- Suggest: "All artifacts created! You can now implement this change or archive it."
- STOP
---
**If artifacts are ready to create** (status shows artifacts with \`status: "ready"\`):
- Pick the FIRST artifact with \`status: "ready"\` from the status output
- Get its instructions:
\`\`\`bash
openspec instructions <artifact-id> --change "<name>" --json
\`\`\`
- Parse the JSON to get template, dependencies, and what it unlocks
- **Create the artifact file** using the template as a starting point:
- Read any completed dependency files for context
- Fill in the template based on context and user's goals
- Write to the output path specified in instructions
- Show what was created and what's now unlocked
- STOP after creating ONE artifact
---
**If no artifacts are ready (all blocked)**:
- This shouldn't happen with a valid schema
- Show status and suggest checking for issues
4. **After creating an artifact, show progress**
\`\`\`bash
openspec status --change "<name>"
\`\`\`
**Output**
After each invocation, show:
- Which artifact was created
- Current progress (N/M complete)
- What artifacts are now unlocked
- Prompt: "Run \`/opsx:continue\` to create the next artifact"
**Artifact Creation Guidelines**
When filling in templates:
- **proposal.md**: Ask user about the change if not clear. Fill in Why, What Changes, Capabilities, Impact.
- **IMPORTANT**: The Capabilities section is critical. Before filling it in:
- Check \`openspec/specs/\` for existing capabilities
- List new capabilities with kebab-case names (e.g., \`user-auth\`, \`data-export\`)
- List modified capabilities that need spec updates
- Each capability listed will need a corresponding spec file in the next phase.
- **specs/*.md**: Create one spec per capability listed in the proposal. Use \`specs/<capability-name>/spec.md\` path.
- **design.md**: Document technical decisions, architecture, and implementation approach.
- **tasks.md**: Break down implementation into checkboxed tasks based on specs and design.
**Guardrails**
- Create ONE artifact per invocation
- Always read dependency artifacts before creating a new one
- 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`
};
}
/**
* Template for /opsx:apply slash command
*/
export function getOpsxApplyCommandTemplate(): CommandTemplate {
return {
name: 'OPSX: Apply',
description: 'Implement tasks from an OpenSpec change (Experimental)',
category: 'Workflow',
tags: ['workflow', 'artifacts', 'experimental'],
content: `Implement tasks from an OpenSpec change.
**Input**: Optionally specify \`--change <name>\` after \`/opsx:apply\`. If omitted, MUST prompt for available changes.
**Steps**
1. **If no change name provided, prompt for selection**
Run \`openspec list --json\` to get available changes. Use the **AskUserQuestion tool** to let the user select.
Show changes that have tasks.md (implementation-ready).
Mark changes with incomplete tasks as "(In Progress)".
**IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
2. **Get apply instructions**
\`\`\`bash
openspec instructions apply --change "<name>" --json
\`\`\`
This returns:
- Context file paths (proposal, specs, design, tasks)
- 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
3. **Read context files**
Read the files listed in \`contextFiles\`:
- \`proposal\` - why and what
- \`specs\` - requirements and scenarios (use glob pattern to find all)
- \`design\` - technical approach (if exists)
- \`tasks\` - the implementation checklist
4. **Show current progress**
Display:
- Progress: "N/M tasks complete"
- Remaining tasks overview
- Dynamic instruction from CLI
5. **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 tasks.md: \`- [ ]\` → \`- [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
6. **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: <change-name>
Working on task 3/7: <task description>
[...implementation happening...]
✓ Task complete
Working on task 4/7: <task description>
[...implementation happening...]
✓ Task complete
\`\`\`
**Output On Completion**
\`\`\`
## Implementation Complete
**Change:** <change-name>
**Progress:** 7/7 tasks complete ✓
### Completed This Session
- [x] Task 1
- [x] Task 2
...
All tasks complete! Ready to archive this change.
\`\`\`
**Output On Pause (Issue Encountered)**
\`\`\`
## Implementation Paused
**Change:** <change-name>
**Progress:** 4/7 tasks complete
### Issue Encountered
<description of the issue>
**Options:**
1. <option 1>
2. <option 2>
3. Other approach
What would you like to do?
\`\`\`
**Guardrails**
- Keep going through tasks until done or blocked
- Always read context before starting (specs, design)
- If task is ambiguous, pause and ask before implementing
- If implementation reveals issues, pause and suggest artifact updates
- Keep code changes minimal and scoped to each task
- Update task checkbox immediately after completing each task
- Pause on errors, blockers, or unclear requirements - don't guess
**Fluid Workflow Integration**
This skill supports the "actions on a change" model:
- **Can be invoked anytime**: Before all artifacts are done (if tasks.md exists), after partial implementation, interleaved with other actions
- **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly`
};
}