Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# The skills.sh distribution files are generated LF-only and compared
# byte-for-byte by test/core/templates/skillssh-parity.test.ts. Force LF on
# checkout so Windows autocrlf doesn't turn them into CRLF and fail parity.
skills/** text eol=lf
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"scripts": {
"lint": "eslint src/",
"build": "node build.js",
"generate:skills": "node scripts/generate-skillssh.mjs",
"dev": "tsc --watch",
"dev:cli": "pnpm build && node bin/openspec.js",
"test": "vitest run",
Expand Down
45 changes: 45 additions & 0 deletions scripts/generate-skillssh.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env node

/**
* Generate the static skills.sh distribution of the OpenSpec workflow skills.
*
* skills.sh installs skills by reading committed `SKILL.md` files straight from
* a GitHub repo (`npx skills add Fission-AI/OpenSpec`). OpenSpec normally
* *generates* these skills into a user's project via `openspec init`, so this
* script mirrors that same output into a committed `skills/<name>/SKILL.md`
* tree that skills.sh can discover.
*
* The committed copies are kept honest by `test/core/templates/skillssh-parity.test.ts`,
* which regenerates and diffs against disk. Run this after any skill-template
* change: `pnpm build && pnpm generate:skills`.
*/

import { mkdirSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';

import { getSkillTemplates, generateSkillContent } from '../dist/core/shared/skill-generation.js';
import { stripVolatileFrontmatter, SKILLS_DIR } from './skillssh-shared.mjs';

const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
const outDir = join(repoRoot, SKILLS_DIR);

// Remove existing skill subdirectories (clears any renamed/removed skills) but
// preserve top-level files like README.md.
mkdirSync(outDir, { recursive: true });
for (const entry of readdirSync(outDir, { withFileTypes: true })) {
if (entry.isDirectory()) {
rmSync(join(outDir, entry.name), { recursive: true, force: true });
}
}

let count = 0;
for (const { template, dirName } of getSkillTemplates()) {
const content = stripVolatileFrontmatter(generateSkillContent(template, 'skills.sh'));
const skillDir = join(outDir, dirName);
mkdirSync(skillDir, { recursive: true });
writeFileSync(join(skillDir, 'SKILL.md'), content, 'utf8');
count++;
}

console.log(`Generated ${count} skills into ${SKILLS_DIR}/`);
16 changes: 16 additions & 0 deletions scripts/skillssh-shared.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Shared helpers for the skills.sh distribution generator and its parity test.
*/

/** Directory (repo-relative) that skills.sh scans for `SKILL.md` files. */
export const SKILLS_DIR = 'skills';

/**
* Drop the per-release `generatedBy` frontmatter line so the committed
* skills.sh copies stay byte-stable across OpenSpec version bumps. The line is
* meaningful only for skills that `openspec init` writes into a project; in the
* standalone distribution it would just churn the files on every release.
*/
export function stripVolatileFrontmatter(content) {
return content.replace(/^ {2}generatedBy: .*\n/m, '');
}
19 changes: 19 additions & 0 deletions skills/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# OpenSpec skills for skills.sh

Install the OpenSpec workflow skills into any [skills.sh](https://skills.sh)-compatible agent:

```bash
npx skills add Fission-AI/OpenSpec
```

Each `openspec-*/SKILL.md` here is the same skill `openspec init` writes into a
project. The skills drive the `openspec` CLI, so for the full setup (CLI +
`openspec/` project scaffolding + slash commands) run:

```bash
npx openspec@latest init
```

> These files are generated from the skill templates — do not edit by hand. Run
> `pnpm build && pnpm generate:skills` after changing a template;
> `skillssh-parity.test.ts` fails if they drift.
159 changes: 159 additions & 0 deletions skills/openspec-apply-change/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
---
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.
allowed-tools: Bash(openspec:*)
license: MIT
compatibility: Requires openspec CLI.
metadata:
author: openspec
version: "1.0"
---

Implement tasks from an OpenSpec change.

**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store <id>` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

**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.

**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: <name>" and how to override (e.g., `/opsx:apply <other>`).

2. **Check status to understand the schema**
```bash
openspec status --change "<name>" --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 "<name>" --json
```

This returns:
- `contextFiles`: artifact ID -> array of concrete file paths (varies by schema - could be proposal/specs/design/tasks or spec/tests/implementation/docs)
- 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 openspec-continue-change
- If `state: "all_done"`: congratulate, suggest archive
- Otherwise: proceed to implementation

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: <change-name> (schema: <schema-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>
**Schema:** <schema-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>
**Schema:** <schema-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 files before starting (from the apply instructions output)
- 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
- Use contextFiles from CLI output, don't assume specific file names

**Fluid Workflow Integration**

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
117 changes: 117 additions & 0 deletions skills/openspec-archive-change/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
---
name: openspec-archive-change
description: Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.
allowed-tools: Bash(openspec:*)
license: MIT
compatibility: Requires openspec CLI.
metadata:
author: openspec
version: "1.0"
---

Archive a completed change in the experimental workflow.

**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store <id>` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root.

**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.

**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 only active changes (not already archived).
Include the schema used for each change if available.

**IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.

2. **Check artifact completion status**

Run `openspec status --change "<name>" --json` to check artifact completion.

Parse the JSON to understand:
- `schemaName`: The workflow being used
- `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context
- `artifacts`: List of artifacts with their status (`done` or other)

**If any artifacts are not `done`:**
- Display warning listing incomplete artifacts
- Use **AskUserQuestion tool** to confirm user wants to proceed
- Proceed if user confirms

3. **Check task completion status**

Read the tasks file (typically `tasks.md`) to check for incomplete tasks.

Count tasks marked with `- [ ]` (incomplete) vs `- [x]` (complete).

**If incomplete tasks found:**
- Display warning showing count of incomplete tasks
- Use **AskUserQuestion tool** to confirm user wants to proceed
- Proceed if user confirms

**If no tasks file exists:** Proceed without task-related warning.

4. **Assess delta spec sync state**

Use `artifactPaths.specs.existingOutputPaths` from status JSON to check for delta specs. If none exist, proceed without sync prompt.

**If delta specs exist:**
- Compare each delta spec with its corresponding main spec at `openspec/specs/<capability>/spec.md`
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
- Determine what changes would be applied (adds, modifications, removals, renames)
- Show a combined summary before prompting

**Prompt options:**
- If changes needed: "Sync now (recommended)", "Archive without syncing"
- If already synced: "Archive now", "Sync anyway", "Cancel"

If user chooses sync, use Task tool (subagent_type: "general-purpose", prompt: "Use Skill tool to invoke openspec-sync-specs for change '<name>'. Delta spec analysis: <include the analyzed delta spec summary>"). Proceed to archive regardless of choice.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

5. **Perform the archive**

Create an `archive` directory under `planningHome.changesDir` if it doesn't exist:
```bash
mkdir -p "<planningHome.changesDir>/archive"
```

Generate target name using current date: `YYYY-MM-DD-<change-name>`

**Check if target already exists:**
- If yes: Fail with error, suggest renaming existing archive or using different date
- If no: Move `changeRoot` to the archive directory

```bash
mv "<changeRoot>" "<planningHome.changesDir>/archive/YYYY-MM-DD-<name>"
```

6. **Display summary**

Show archive completion summary including:
- Change name
- Schema that was used
- Archive location
- Whether specs were synced (if applicable)
- Note about any warnings (incomplete artifacts/tasks)

**Output On Success**

```
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
## Archive Complete

**Change:** <change-name>
**Schema:** <schema-name>
**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-<name>/
**Specs:** ✓ Synced to main specs (or "No delta specs" or "Sync skipped")

All artifacts complete. All tasks complete.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
```

**Guardrails**
- Always prompt for change selection if not provided
- Use artifact graph (openspec status --json) for completion checking
- Don't block archive on warnings - just inform and confirm
- Preserve .openspec.yaml when moving to archive (it moves with the directory)
- Show clear summary of what happened
- If sync is requested, use openspec-sync-specs approach (agent-driven)
- If delta specs exist, always run the sync assessment and show the combined summary before prompting
Loading
Loading