From 6524c78a6cbb2caa6696117c500c38ea6b41f686 Mon Sep 17 00:00:00 2001 From: Tabish Bidiwale Date: Sat, 24 Jan 2026 14:36:21 -0800 Subject: [PATCH 01/14] feat(skills): add opsx:onboard guided workflow skill Add a new onboard skill that walks users through their first complete OpenSpec workflow cycle. The skill provides interactive guidance through task selection, change creation, artifact building, implementation, and archiving. Also includes: - New README with updated branding and workflow examples - Documentation structure placeholders - Change artifacts for the onboard skill feature --- README_NEW.md | 163 +++++ assets/openspec_bg.png | Bin 0 -> 94149 bytes assets/openspec_bg2.png | Bin 0 -> 35032 bytes docs/README_RENEWAL_PROMPTS.md | 560 ++++++++++++++++++ docs/cli.md | 2 + docs/commands.md | 2 + docs/concepts.md | 2 + docs/customization.md | 2 + docs/getting-started.md | 2 + docs/i18n.md | 2 + docs/workflows.md | 2 + .../add-opsx-onboard-skill/.openspec.yaml | 2 + .../changes/add-opsx-onboard-skill/design.md | 115 ++++ .../add-opsx-onboard-skill/proposal.md | 27 + .../specs/opsx-onboard-skill/spec.md | 162 +++++ .../changes/add-opsx-onboard-skill/tasks.md | 21 + src/core/shared/skill-generation.ts | 4 + src/core/templates/skill-templates.ts | 553 +++++++++++++++++ 18 files changed, 1621 insertions(+) create mode 100644 README_NEW.md create mode 100644 assets/openspec_bg.png create mode 100644 assets/openspec_bg2.png create mode 100644 docs/README_RENEWAL_PROMPTS.md create mode 100644 docs/cli.md create mode 100644 docs/commands.md create mode 100644 docs/concepts.md create mode 100644 docs/customization.md create mode 100644 docs/getting-started.md create mode 100644 docs/i18n.md create mode 100644 docs/workflows.md create mode 100644 openspec/changes/add-opsx-onboard-skill/.openspec.yaml create mode 100644 openspec/changes/add-opsx-onboard-skill/design.md create mode 100644 openspec/changes/add-opsx-onboard-skill/proposal.md create mode 100644 openspec/changes/add-opsx-onboard-skill/specs/opsx-onboard-skill/spec.md create mode 100644 openspec/changes/add-opsx-onboard-skill/tasks.md diff --git a/README_NEW.md b/README_NEW.md new file mode 100644 index 000000000..ecbc48047 --- /dev/null +++ b/README_NEW.md @@ -0,0 +1,163 @@ +

+ + + + OpenSpec logo + + +

+ +

+ CI + npm version + License: MIT + Discord +

+ +The most loved spec framework. + +Our philosophy: + +``` +→ fluid not rigid +→ iterative not waterfall +→ easy not complex +→ built for brownfield not just greenfield +→ scalable from personal projects to enterprises +``` + +> [!TIP] +> **New workflow now available!** We've rebuilt OpenSpec with a new artifact-guided workflow. Run `/opsx:onboard` to get started. → [Learn more here](#) + +

+ Follow @0xTab on X for updates · Join the OpenSpec Discord for help and questions. +

+ +### Teams + +Using OpenSpec in a team? [Email here](mailto:teams@openspec.dev) for access to our Slack channel. + + + +## See it in action + +``` +You: /opsx:new add-dark-mode +AI: Created openspec/changes/add-dark-mode/ + Ready to create: proposal + +You: /opsx:ff +AI: ✓ proposal.md — why we're doing this, what's changing + ✓ specs/ — requirements and scenarios + ✓ design.md — technical approach + ✓ tasks.md — implementation checklist + Ready for implementation! + +You: /opsx:apply +AI: Implementing tasks... + ✓ 1.1 Add theme context provider + ✓ 1.2 Create toggle component + ✓ 2.1 Add CSS variables + ✓ 2.2 Wire up localStorage + All tasks complete! + +You: /opsx:archive +AI: Archived to openspec/changes/archive/2025-01-23-add-dark-mode/ + Specs updated. Ready for the next feature. +``` + +## Quick Start + +**Requires Node.js 20.19.0 or higher.** + +Install OpenSpec globally: + +```bash +npm install -g @fission-ai/openspec@latest +``` + +Then navigate to your project directory and initialize: + +```bash +cd your-project +openspec init +``` + +Now tell your AI: `/opsx:new ` + +> [!NOTE] +> Not sure if your tool is supported? [View the full list](link) – we support 20+ tools and growing. + +> [!NOTE] +> Also works with pnpm, yarn, bun, and nix. [See installation options](link). + +## Docs + +→ **[Getting Started](link)**: first steps
+→ **[Workflows](link)**: combo's and patterns
+→ **[Commands](link)**: slash commands & skills
+→ **[CLI](link)**: terminal reference
+→ **[Concepts](link)**: how it all fits
+→ **[i18n](link)**: multi-language support
+→ **[Customization](link)**: make it yours + + +## Why OpenSpec? + +AI coding assistants are powerful but unpredictable when requirements live only in chat history. OpenSpec adds a lightweight spec layer so you agree on what to build before any code is written. + +- **Agree before you build** — human and AI align on specs before code gets written +- **Stay organized** — each change gets its own folder with proposal, specs, design, and tasks +- **Work fluidly** — update any artifact anytime, no rigid phase gates +- **Use your tools** — works with 20+ AI assistants via slash commands + +### How we compare + +**vs. [Spec Kit](https://github.com/github/spec-kit)** (GitHub) — Thorough but heavyweight. Rigid phase gates, lots of markdown, Python setup. OpenSpec is lighter and lets you iterate freely. + +**vs. [Kiro](https://kiro.dev)** (AWS) — Powerful but you're locked into their IDE and limited to Claude models. OpenSpec works with the tools you already use. + +**vs. nothing** — AI coding without specs means vague prompts and unpredictable results. OpenSpec brings predictability without the ceremony. + +## Updating OpenSpec + +1. **Upgrade the package** + ```bash + npm install -g @fission-ai/openspec@latest + ``` +2. **Refresh agent instructions** + - Run `openspec update` inside each project to regenerate AI guidance and ensure the latest slash commands are active. + +## Contributing + +- Install dependencies: `pnpm install` +- Build: `pnpm run build` +- Test: `pnpm test` +- Develop CLI locally: `pnpm run dev` or `pnpm run dev:cli` +- Conventional commits (one-line): `type(scope): subject` + +## Other + +
+Telemetry + +OpenSpec collects anonymous usage stats. + +We collect only command names and version to understand usage patterns. No arguments, paths, content, or PII. Automatically disabled in CI. + +**Opt-out:** `export OPENSPEC_TELEMETRY=0` or `export DO_NOT_TRACK=1` + +
+ +
+Maintainers & Advisors + +See [MAINTAINERS.md](MAINTAINERS.md) for the list of core maintainers and advisors who help guide the project. + +
+ + + +## License + +MIT diff --git a/assets/openspec_bg.png b/assets/openspec_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..dd59888334bacdd2d456e03381e4ca7a7f982d0d GIT binary patch literal 94149 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≺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 P<-|ipwR;73OkVvTz{-jq literal 0 HcmV?d00001 diff --git a/docs/README_RENEWAL_PROMPTS.md b/docs/README_RENEWAL_PROMPTS.md new file mode 100644 index 000000000..52a53b846 --- /dev/null +++ b/docs/README_RENEWAL_PROMPTS.md @@ -0,0 +1,560 @@ +# README Renewal Plan: Documentation Prompts + +This file contains prompts for AI agents to write each documentation file. Each prompt is self-contained and designed to be run in a fresh context session. + +--- + +## 1. Getting Started (`docs/getting-started.md`) + +``` +You are writing documentation for OpenSpec, a spec-driven development framework for AI coding assistants. + +**Your task:** Write the Getting Started guide at `docs/getting-started.md`. + +**Note:** Installation and initialization are already covered in the main README. This guide focuses on understanding how OpenSpec works after you've run `openspec init`. + +**Context about OpenSpec:** +- OpenSpec helps humans and AI coding assistants agree on what to build before code is written +- It uses a folder structure: `openspec/specs/` (source of truth) and `openspec/changes/` (proposed updates) +- The primary workflow uses OPSX commands: `/opsx:new`, `/opsx:ff`, `/opsx:apply`, `/opsx:archive` + +**Philosophy:** +- Fluid not rigid +- Iterative not waterfall +- Easy not complex +- Built for brownfield not just greenfield + +**Target audience:** Developers who have installed OpenSpec and want to understand how it works. + +**What to cover:** + +1. **How It Works** - The overall flow with an ASCII diagram: + ``` + ┌────────────────────┐ + │ Start a Change │ /opsx:new + └────────┬───────────┘ + │ + ▼ + ┌────────────────────┐ + │ Create Artifacts │ /opsx:ff or /opsx:continue + │ (proposal, specs, │ + │ design, tasks) │◄──── iterate as needed + └────────┬───────────┘ + │ + ▼ + ┌────────────────────┐ + │ Implement Tasks │ /opsx:apply + │ (AI writes code) │──── can update artifacts mid-flight + └────────┬───────────┘ + │ + ▼ + ┌────────────────────┐ + │ Archive & Merge │ /opsx:archive + │ Specs │ + └────────────────────┘ + ``` + +2. **What OpenSpec Creates** - The folder structure after init: + ``` + openspec/ + ├── specs/ # Source of truth (your system's behavior) + │ └── / + │ └── spec.md + ├── changes/ # Proposed updates (one folder per change) + │ └── / + │ ├── proposal.md + │ ├── design.md + │ ├── tasks.md + │ └── specs/ # Delta specs (what's changing) + │ └── / + │ └── spec.md + └── config.yaml # Project configuration (optional) + ``` + +3. **Understanding Artifacts** - What each file does: + - `proposal.md` - The "why" and "what" (intent, scope, approach) + - `specs/` - Delta specs showing ADDED/MODIFIED/REMOVED requirements + - `design.md` - The "how" (technical approach, architecture decisions) + - `tasks.md` - Implementation checklist with checkboxes + +4. **How Delta Specs Work** - The key concept: + - Delta specs show changes relative to current specs + - Use sections: `## ADDED Requirements`, `## MODIFIED Requirements`, `## REMOVED Requirements` + - Each requirement has scenarios (Given/When/Then or similar) + - On archive, deltas merge into main specs + +5. **Example: Your First Change** - Walk through a real example: + - User asks to add dark mode + - AI creates change folder with artifacts + - Show what each generated file looks like + - Implementation updates task checkboxes + - Archive merges specs + +6. **Next Steps** - Links to Workflows, Commands, Concepts, Customization + +**Style guidelines:** +- Use ASCII diagrams to visualize structure and flow +- Show real file examples (like the 2FA example from old README) +- Explain concepts as you introduce them +- Keep it scannable with clear headers +- No emojis + +**Read these files for context:** +- `README.md` (old README - has good examples of generated specs and deltas) +- `README_NEW.md` (new product positioning) +- `docs/experimental-workflow.md` (OPSX workflow details) + +Write the complete documentation file now. +``` + +--- + +## 2. Workflows (`docs/workflows.md`) + +``` +You are writing documentation for OpenSpec, a spec-driven development framework for AI coding assistants. + +**Your task:** Write the Workflows guide at `docs/workflows.md`. + +**Context about OpenSpec:** +- OpenSpec uses an artifact-based workflow called OPSX +- Artifacts: proposal → specs → design → tasks → implementation +- Dependencies enable progress but don't lock you into phases +- You can update any artifact anytime (fluid, not rigid) +- Changes live in `openspec/changes//` folders + +**OPSX Commands:** +| Command | Purpose | +|---------|---------| +| `/opsx:explore` | Think through ideas before committing | +| `/opsx:new` | Start a new change | +| `/opsx:continue` | Create the next artifact based on dependencies | +| `/opsx:ff` | Fast-forward - create all planning artifacts at once | +| `/opsx:apply` | Implement tasks, can update artifacts mid-implementation | +| `/opsx:sync` | Sync delta specs to main specs | +| `/opsx:verify` | Verify implementation matches artifacts | +| `/opsx:archive` | Archive completed change | + +**Artifact flow:** +``` +proposal ──→ specs ──→ design ──→ tasks ──→ implement + ▲ ▲ ▲ │ + └───────────┴──────────┴────────────────────┘ + update as you learn +``` + +**Target audience:** Users who understand the basics and want to learn effective patterns. + +**What to cover:** +1. The OPSX philosophy (actions not phases, fluid iteration) +2. Common workflow patterns: + - **Quick feature**: `/opsx:new` → `/opsx:ff` → `/opsx:apply` → `/opsx:archive` + - **Exploratory**: `/opsx:explore` → `/opsx:new` → `/opsx:continue` (step by step) + - **Mid-flight correction**: updating specs/design during `/opsx:apply` + - **Parallel changes**: working on multiple changes simultaneously +3. When to use `/opsx:ff` vs `/opsx:continue` +4. When to update vs start fresh (same intent = update, different work = new change) +5. Best practices: + - Keep changes focused + - Use `/opsx:explore` for unclear requirements + - Sync specs regularly + - Verify before archiving + +**Style guidelines:** +- Use diagrams (ASCII art) where helpful +- Include real-world examples +- Show the conversation flow between user and AI +- Keep sections scannable + +**Read these files for context:** +- `docs/experimental-workflow.md` (full OPSX documentation) + +Write the complete documentation file now. +``` + +--- + +## 3. Commands (`docs/commands.md`) + +``` +You are writing documentation for OpenSpec, a spec-driven development framework for AI coding assistants. + +**Your task:** Write the Commands reference at `docs/commands.md`. + +**Context about OpenSpec:** +- OpenSpec provides slash commands that work with AI coding assistants +- Commands are invoked in the AI chat (e.g., `/opsx:new add-dark-mode`) +- Different AI tools use different command formats (some use `:`, some use `-`) +- The OPSX workflow is the primary/recommended workflow + +**OPSX Commands (primary workflow):** + +| Command | What it does | Arguments | +|---------|--------------|-----------| +| `/opsx:explore` | Think through ideas, investigate problems | Optional: topic to explore | +| `/opsx:new` | Start a new change | Optional: change name, `--schema` | +| `/opsx:continue` | Create next ready artifact | Optional: change name | +| `/opsx:ff` | Fast-forward all planning artifacts | Optional: change name | +| `/opsx:apply` | Implement tasks | Optional: change name | +| `/opsx:sync` | Sync delta specs to main | Optional: change name | +| `/opsx:verify` | Verify implementation completeness | Optional: change name | +| `/opsx:archive` | Archive completed change | Optional: change name | +| `/opsx:bulk-archive` | Archive multiple changes | Required: change names | + +**Legacy Commands (still supported):** +| Command | What it does | +|---------|--------------| +| `/openspec:proposal` | Create proposal (all-at-once, older workflow) | +| `/openspec:apply` | Apply change | +| `/openspec:archive` | Archive change | + +**Supported AI Tools:** +- Claude Code: `/opsx:new`, `/openspec:proposal` +- Cursor: `/opsx-new`, `/openspec-proposal` +- Windsurf: `/opsx-new`, `/openspec-proposal` +- GitHub Copilot: `/openspec-proposal` +- And 15+ more tools + +**Target audience:** Users looking up specific command syntax and options. + +**What to cover:** +1. Quick reference table of all commands +2. Detailed documentation for each OPSX command: + - Syntax + - Arguments and options + - What it creates/modifies + - Example usage + - Tips +3. Command format by AI tool (table showing syntax variations) +4. Legacy commands (brief, point to OPSX as recommended) +5. Troubleshooting common command issues + +**Style guidelines:** +- Reference documentation style (scannable, searchable) +- Consistent format for each command +- Include example invocations +- Note tool-specific variations + +Write the complete documentation file now. +``` + +--- + +## 4. CLI (`docs/cli.md`) + +``` +You are writing documentation for OpenSpec, a spec-driven development framework for AI coding assistants. + +**Your task:** Write the CLI reference at `docs/cli.md`. + +**Context about OpenSpec:** +- OpenSpec has a terminal CLI (`openspec`) separate from the AI slash commands +- CLI is used for setup, validation, viewing status, and management +- Install with: `npm install -g @fission-ai/openspec@latest` + +**CLI Commands:** + +``` +openspec init [path] # Initialize OpenSpec in project +openspec update [path] # Update instruction files after upgrade +openspec list [--specs] # List changes (or specs with --specs) +openspec view # Interactive dashboard +openspec show # Show change or spec details +openspec validate # Validate change or spec +openspec archive # Archive completed change +openspec status --change # Show artifact completion status +openspec instructions # Get enriched instructions for artifact +openspec schemas # List available workflow schemas +openspec schema init # Create new custom schema +openspec schema fork # Fork existing schema +openspec schema validate # Validate schema structure +openspec config # View/modify global config +openspec feedback # Submit feedback +openspec completion # Shell completions +``` + +**Target audience:** Users who need CLI reference for terminal operations. + +**What to cover:** +1. Installation and verification +2. Core commands (init, update, list, view, show) +3. Validation commands (validate) +4. Archive commands (archive) +5. Status and debugging (status, instructions, templates) +6. Schema management (schemas, schema init/fork/validate/which) +7. Configuration (config) +8. Utility commands (feedback, completion) +9. Global options (--no-color, --help, --version) +10. Exit codes and error handling + +**Style guidelines:** +- Man page style reference documentation +- Consistent format: syntax, description, options, examples +- Include common flags and their effects +- Show expected output where helpful + +**To get accurate CLI info, run:** +```bash +openspec --help +openspec --help +``` + +Write the complete documentation file now. +``` + +--- + +## 5. Concepts (`docs/concepts.md`) + +``` +You are writing documentation for OpenSpec, a spec-driven development framework for AI coding assistants. + +**Your task:** Write the Concepts guide at `docs/concepts.md`. + +**Context about OpenSpec:** + +**Philosophy:** +- Fluid not rigid (no phase gates) +- Iterative not waterfall (update as you learn) +- Easy not complex (lightweight setup) +- Brownfield-first (works with existing codebases, not just 0→1) + +**Core Concepts:** + +1. **Specs** (`openspec/specs/`) + - Source of truth for your system's behavior + - Organized by domain (e.g., `specs/auth/`, `specs/payments/`) + - Use structured format: Requirements → Scenarios + +2. **Changes** (`openspec/changes/`) + - Proposed modifications to specs + - Each change is a folder with artifacts + - Contains "delta specs" showing what's added/modified/removed + +3. **Artifacts** (within a change) + - `proposal.md` - Why and what (intent, scope, approach) + - `specs/` - Delta specs (ADDED/MODIFIED/REMOVED requirements) + - `design.md` - Technical approach + - `tasks.md` - Implementation checklist + +4. **Delta Specs** + - Show changes relative to current specs + - Sections: `## ADDED Requirements`, `## MODIFIED Requirements`, `## REMOVED Requirements` + - Merged into main specs on archive + +5. **Schemas** + - Define artifact types and dependencies + - Default: `spec-driven` (proposal → specs → design → tasks) + - Alternative: `tdd` (tests → implementation → docs) + - Custom schemas supported + +6. **Archive** + - When change is complete, archive merges delta specs into main specs + - Change folder moves to `openspec/changes/archive/` + - Creates audit trail of all changes + +**The Flow:** +``` +Intent → Proposal → Specs → Design → Tasks → Implementation → Archive + (agree) (what) (how) (steps) (code) (merge) +``` + +**Key Differentiators:** +- vs. spec-kit (GitHub): Lighter, no phase gates +- vs. Kiro (AWS): Tool-agnostic, not locked to one IDE +- vs. nothing: Predictability without ceremony + +**Target audience:** Users who want to understand the "why" behind OpenSpec's design. + +**What to cover:** +1. Philosophy and design principles +2. Specs: what they are, structure, organization +3. Changes: the change folder structure +4. Artifacts: each type and its purpose +5. Delta specs: format and merge behavior +6. Schemas: what they are, built-in vs custom +7. The archive process +8. Glossary of terms + +**Style guidelines:** +- Explain the "why" not just the "what" +- Use diagrams to show relationships +- Include examples of each concept +- Build understanding progressively + +Write the complete documentation file now. +``` + +--- + +## 6. i18n (`docs/i18n.md`) + +``` +You are writing documentation for OpenSpec, a spec-driven development framework for AI coding assistants. + +**Your task:** Write the i18n (internationalization) guide at `docs/i18n.md`. + +**Context about OpenSpec:** +- OpenSpec generates instruction files that AI assistants read +- These instructions are currently in English +- Teams may want instructions in other languages +- Spec content itself can be in any language (user-controlled) + +**Current state:** +- OpenSpec CLI and generated files are English-only +- No built-in translation mechanism yet +- Community interest in multi-language support + +**Target audience:** International teams and contributors interested in localization. + +**What to cover:** +1. Current language support status +2. What can be localized: + - CLI output (future) + - Generated instruction files (future) + - Spec content (user-controlled, any language works) + - Templates (can be customized via schemas) +3. Workarounds for non-English teams: + - Custom schemas with translated templates + - Writing specs in your preferred language + - AI assistants can respond in user's language regardless +4. Contributing translations (if/when supported) +5. Roadmap/plans for i18n support + +**Note:** This may be a shorter document if i18n support is limited. Be honest about current state while showing the path forward. + +**Style guidelines:** +- Be honest about current limitations +- Provide practical workarounds +- Welcome community contributions +- Keep it brief if there's not much to cover yet + +**Check the codebase for any existing i18n infrastructure or configuration.** + +Write the complete documentation file now. +``` + +--- + +## 7. Customization (`docs/customization.md`) + +``` +You are writing documentation for OpenSpec, a spec-driven development framework for AI coding assistants. + +**Your task:** Write the Customization guide at `docs/customization.md`. + +**Context about OpenSpec:** +- OpenSpec is designed to be hackable and customizable +- Users can create custom schemas (artifact types + dependencies) +- Templates are plain Markdown files you can edit +- Project config injects context into all artifacts + +**Customization Points:** + +1. **Project Config** (`openspec/config.yaml`) + ```yaml + schema: spec-driven + context: | + Tech stack: TypeScript, React, Node.js + Testing: Vitest, Playwright + rules: + proposal: + - Include rollback plan + specs: + - Use Given/When/Then format + ``` + +2. **Custom Schemas** (`openspec/schemas//`) + - `schema.yaml` - defines artifacts and dependencies + - `templates/*.md` - instruction templates for each artifact + + Example schema.yaml: + ```yaml + name: research-first + artifacts: + - id: research + generates: research.md + requires: [] + - id: proposal + generates: proposal.md + requires: [research] + - id: tasks + generates: tasks.md + requires: [proposal] + ``` + +3. **Schema Commands:** + ```bash + openspec schema init # Create new schema interactively + openspec schema fork # Fork existing schema + openspec schema validate # Validate schema structure + openspec schema which # See where schema resolves from + ``` + +4. **Template Customization:** + - Edit templates in `openspec/schemas//templates/` + - Templates are Markdown with placeholders + - Changes take effect immediately (no rebuild) + +5. **Schema Precedence:** + 1. CLI flag (`--schema tdd`) + 2. Change metadata (`.openspec.yaml` in change dir) + 3. Project config (`openspec/config.yaml`) + 4. Default (`spec-driven`) + +**Built-in Schemas:** +- `spec-driven` (default): proposal → specs → design → tasks +- `tdd`: spec → tests → implementation → docs + +**Target audience:** Power users who want to adapt OpenSpec to their workflow. + +**What to cover:** +1. Project configuration (config.yaml) + - Schema selection + - Context injection + - Per-artifact rules +2. Custom schemas + - When to create one + - Schema structure + - Creating with `schema init` + - Forking with `schema fork` +3. Template customization + - Template format + - Available placeholders + - Best practices +4. Schema resolution and precedence +5. Validation and troubleshooting +6. Examples: + - Research-first workflow + - TDD workflow + - Documentation-heavy workflow + +**Style guidelines:** +- Include complete, working examples +- Show before/after for customizations +- Explain what each customization affects +- Include troubleshooting tips + +**Read these files for context:** +- `docs/experimental-workflow.md` (has config and schema details) + +Write the complete documentation file now. +``` + +--- + +## Usage Instructions + +1. Copy each prompt (everything between the triple backticks) into a fresh AI session +2. Provide the relevant files when the prompt asks to read them +3. Review and edit the generated documentation +4. Update the links in `README_NEW.md` to point to the new doc files + +## Post-Generation Checklist + +- [ ] Review each doc for accuracy against current codebase +- [ ] Ensure consistent terminology across all docs +- [ ] Add cross-references between related docs +- [ ] Update `README_NEW.md` with correct doc links +- [ ] Test all code examples and commands +- [ ] Get team review before publishing diff --git a/docs/cli.md b/docs/cli.md new file mode 100644 index 000000000..432929e78 --- /dev/null +++ b/docs/cli.md @@ -0,0 +1,2 @@ +# CLI + diff --git a/docs/commands.md b/docs/commands.md new file mode 100644 index 000000000..2831b915e --- /dev/null +++ b/docs/commands.md @@ -0,0 +1,2 @@ +# Commands + diff --git a/docs/concepts.md b/docs/concepts.md new file mode 100644 index 000000000..e834417d3 --- /dev/null +++ b/docs/concepts.md @@ -0,0 +1,2 @@ +# Concepts + diff --git a/docs/customization.md b/docs/customization.md new file mode 100644 index 000000000..3df392295 --- /dev/null +++ b/docs/customization.md @@ -0,0 +1,2 @@ +# Customization + diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 000000000..31dd91e80 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,2 @@ +# Getting Started + diff --git a/docs/i18n.md b/docs/i18n.md new file mode 100644 index 000000000..45a791d8c --- /dev/null +++ b/docs/i18n.md @@ -0,0 +1,2 @@ +# i18n + diff --git a/docs/workflows.md b/docs/workflows.md new file mode 100644 index 000000000..7f043c676 --- /dev/null +++ b/docs/workflows.md @@ -0,0 +1,2 @@ +# Workflows + diff --git a/openspec/changes/add-opsx-onboard-skill/.openspec.yaml b/openspec/changes/add-opsx-onboard-skill/.openspec.yaml new file mode 100644 index 000000000..a5a6fec48 --- /dev/null +++ b/openspec/changes/add-opsx-onboard-skill/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-01-24 diff --git a/openspec/changes/add-opsx-onboard-skill/design.md b/openspec/changes/add-opsx-onboard-skill/design.md new file mode 100644 index 000000000..505f94e9c --- /dev/null +++ b/openspec/changes/add-opsx-onboard-skill/design.md @@ -0,0 +1,115 @@ +## Context + +OpenSpec has a complete skill and slash command generation system. Skills are defined in `src/core/templates/skill-templates.ts` as functions that return `SkillTemplate` objects (for Agent Skills) and `CommandTemplate` objects (for slash commands). These are registered in `src/core/shared/skill-generation.ts` and generated during `openspec init` and `openspec update`. + +Existing skills follow a consistent pattern: +- `getXxxSkillTemplate()` returns the skill with name, description, instructions +- `getOpsxXxxCommandTemplate()` returns the slash command with name, description, category, tags, content +- Both are registered in their respective arrays in `skill-generation.ts` + +## Goals / Non-Goals + +**Goals:** +- Add `/opsx:onboard` skill that teaches the OpenSpec workflow through guided practice +- Follow existing patterns for skill/command template generation +- Provide comprehensive narration that explains each step +- Include codebase analysis to suggest real, appropriately-scoped tasks + +**Non-Goals:** +- Creating a separate "demo mode" or simulated workflow (we do real work) +- Adding new CLI commands (this is purely agent instructions) +- Modifying the init/update flow (just adding to the template arrays) + +## Decisions + +### Decision 1: Single Monolithic Skill + +The onboard skill will be a single comprehensive instruction set rather than composing existing skills with flags. + +**Rationale:** +- Slash commands don't support flags (they're just prompts) +- A monolithic skill gives complete control over narration and pacing +- Easier to maintain a single cohesive experience +- Users learn the real commands by seeing them mentioned in narration + +### Decision 2: Codebase Analysis Patterns + +The skill instructions will direct the agent to look for specific patterns when suggesting starter tasks: + +1. TODO/FIXME comments in code +2. Missing error handling (`catch` blocks that swallow errors, no try-catch around risky operations) +3. Functions without tests (cross-reference src/ with test files) +4. Type: `any` in TypeScript files +5. Console.log statements in non-debug code +6. Missing input validation on user-facing inputs +7. Recent git commits (for context on what user is working on) + +**Rationale:** These are universally applicable, easy to detect, and produce well-scoped tasks. + +### Decision 3: Narration Integration Style + +Each phase will follow a pattern: +1. **EXPLAIN** what we're about to do and why (1-2 sentences) +2. **DO** the action (run command, create artifact) +3. **SHOW** what happened +4. **PAUSE** at key transitions (not every step) + +Pauses occur at: +- After task selection (before creating change) +- After drafting proposal (before saving) +- After tasks are generated (before implementation) +- After archive (final recap) + +**Rationale:** Too many pauses becomes tedious. Too few loses the teaching opportunity. These are the natural "chapter breaks." + +### Decision 4: Scope Guardrail Approach + +When user selects a task that's too large, the skill will: +1. Acknowledge the task is valuable +2. Explain why smaller is better for first time +3. Suggest a smaller slice or alternative +4. Let user override if they insist + +**Rationale:** Soft guardrails teach without frustrating. Users learn scope calibration as part of the experience. + +### Decision 5: Template Structure + +The skill template will be ~400-600 lines of instruction text, structured as: + +``` +- Preflight checks (init status) +- Phase 1: Welcome & Setup +- Phase 2: Task Selection (with codebase analysis instructions) +- Phase 3: Explore Demo (brief) +- Phase 4: Change Creation +- Phase 5: Proposal +- Phase 6: Specs +- Phase 7: Design +- Phase 8: Tasks +- Phase 9: Apply (Implementation) +- Phase 10: Archive +- Phase 11: Recap & Next Steps +- Edge cases & graceful exits +``` + +The command template will be identical to the skill template (same content, different wrapper). + +**Rationale:** Following the established pattern where skill and command share the same core instructions. + +## Risks / Trade-offs + +**Risk: Instruction length** +The skill will be significantly longer than existing skills (~500 lines vs ~100-200). +→ Mitigation: This is acceptable since onboarding is inherently comprehensive. Token cost is one-time per session. + +**Risk: Codebase analysis may find nothing** +Some codebases (new projects, very clean code) may not have obvious improvement opportunities. +→ Mitigation: Fall back to asking user what they want to build. Include "add a new feature" as an option. + +**Risk: Task suggestions may be inappropriate** +Agent might suggest tasks that touch sensitive code or have hidden complexity. +→ Mitigation: User always chooses; agent just suggests. Scope estimates help set expectations. + +**Risk: User abandons mid-way** +Onboarding takes ~15 minutes; users may not complete it. +→ Mitigation: Graceful exit handling - note the change is saved, explain how to continue later. diff --git a/openspec/changes/add-opsx-onboard-skill/proposal.md b/openspec/changes/add-opsx-onboard-skill/proposal.md new file mode 100644 index 000000000..b280cc2de --- /dev/null +++ b/openspec/changes/add-opsx-onboard-skill/proposal.md @@ -0,0 +1,27 @@ +## Why + +Users who run `openspec init` are left with files but no clear path to actually using the system. There's a gap between "I have OpenSpec set up" and "I understand the workflow." An onboarding skill would guide users through their first complete change cycle on a real task in their codebase, teaching the workflow by doing it. + +## What Changes + +- Add new `/opsx:onboard` skill that guides users through their first OpenSpec change +- Add corresponding slash command template for editor integrations +- The skill will: + - Analyze the user's codebase to suggest appropriately-scoped starter tasks + - Walk through the full workflow (explore → new → proposal → specs → design → tasks → apply → archive) + - Provide narration explaining each step as it happens + - Result in a real, implemented change in the user's codebase + +## Capabilities + +### New Capabilities +- `opsx-onboard-skill`: The onboarding skill that guides users through their first complete OpenSpec workflow cycle with narration and codebase-aware task suggestions + +### Modified Capabilities + + +## Impact + +- `src/core/templates/skill-templates.ts`: Add `getOnboardSkillTemplate()` and `getOpsxOnboardCommandTemplate()` functions +- `src/core/shared/skill-generation.ts`: Register the new skill and command templates in `getSkillTemplates()` and `getCommandTemplates()` +- Users running `openspec init` or `openspec update` will get the new skill/command files generated diff --git a/openspec/changes/add-opsx-onboard-skill/specs/opsx-onboard-skill/spec.md b/openspec/changes/add-opsx-onboard-skill/specs/opsx-onboard-skill/spec.md new file mode 100644 index 000000000..ffb44743c --- /dev/null +++ b/openspec/changes/add-opsx-onboard-skill/specs/opsx-onboard-skill/spec.md @@ -0,0 +1,162 @@ +## ADDED Requirements + +### Requirement: OPSX Onboard Skill + +The system SHALL provide an `/opsx:onboard` skill that guides users through their first complete OpenSpec workflow cycle with narration and real codebase work. + +#### Scenario: Skill invocation + +- **WHEN** user invokes `/opsx:onboard` +- **THEN** agent checks if OpenSpec is initialized +- **AND** if not initialized, prompts user to run `openspec init` first +- **AND** if initialized, proceeds with onboarding flow + +#### Scenario: Welcome and expectations + +- **WHEN** onboarding begins +- **THEN** agent displays welcome message explaining what will happen +- **AND** sets expectation of ~15 minute duration +- **AND** explains the workflow phases: explore → new → artifacts → apply → archive + +### Requirement: Codebase Analysis for Task Suggestions + +The skill SHALL analyze the user's codebase to suggest appropriately-scoped starter tasks. + +#### Scenario: Codebase scanning + +- **WHEN** onboarding reaches task selection phase +- **THEN** agent scans codebase for small improvement opportunities +- **AND** looks for: TODO/FIXME comments, missing error handling, functions without tests, outdated dependencies, type: any in TypeScript, console.log in production code, missing input validation +- **AND** checks recent git commits for context on current work + +#### Scenario: Task suggestion presentation + +- **WHEN** agent has analyzed codebase +- **THEN** agent presents 3-4 specific task suggestions with scope estimates +- **AND** each suggestion includes: task description, estimated scope (files/lines), why it's a good starter +- **AND** offers option for user to specify their own task + +#### Scenario: Scope guardrail + +- **WHEN** user selects or describes a task that is too large +- **THEN** agent gently redirects toward smaller scope +- **AND** suggests breaking down or deferring the large task +- **AND** offers appropriately-sized alternatives + +### Requirement: Explore Phase Demo + +The skill SHALL briefly demonstrate explore mode before creating a change. + +#### Scenario: Brief explore demonstration + +- **WHEN** task is selected +- **THEN** agent briefly demonstrates `/opsx:explore` by investigating relevant code +- **AND** explains explore mode is for thinking before doing +- **AND** keeps this phase short (not a full exploration session) +- **AND** transitions to change creation + +### Requirement: Guided Artifact Creation + +The skill SHALL guide users through each artifact with narration explaining the purpose. + +#### Scenario: Change creation with narration + +- **WHEN** creating the change directory +- **THEN** agent runs `openspec new change ""` with derived kebab-case name +- **AND** explains what a "change" is (container for thinking and planning) +- **AND** shows the folder structure that was created +- **AND** pauses for user acknowledgment before proceeding + +#### Scenario: Proposal creation with narration + +- **WHEN** creating proposal.md +- **THEN** agent explains proposals capture WHY we're making this change +- **AND** drafts proposal based on selected task +- **AND** shows draft to user for approval before saving +- **AND** explains the sections (Why, What Changes, Capabilities, Impact) + +#### Scenario: Specs creation with narration + +- **WHEN** creating spec files +- **THEN** agent explains specs define WHAT we're building in detail +- **AND** explains the requirement/scenario format +- **AND** creates spec file(s) based on proposal capabilities +- **AND** notes that specs become documentation that stays in sync + +#### Scenario: Design creation with narration + +- **WHEN** creating design.md +- **THEN** agent explains design captures HOW we'll build it +- **AND** notes this is where technical decisions and tradeoffs live +- **AND** for small changes, acknowledges design may be brief +- **AND** creates design based on proposal and specs + +#### Scenario: Tasks creation with narration + +- **WHEN** creating tasks.md +- **THEN** agent explains tasks break work into checkboxes +- **AND** explains these drive the apply phase +- **AND** generates task list from design and specs +- **AND** shows tasks and asks if ready to implement + +### Requirement: Guided Implementation + +The skill SHALL implement tasks with narration connecting back to artifacts. + +#### Scenario: Implementation with narration + +- **WHEN** implementing tasks +- **THEN** agent announces each task before working on it +- **AND** implements the change in the codebase +- **AND** occasionally references how specs/design informed decisions +- **AND** marks each task complete as it finishes +- **AND** keeps narration light (not over-explaining) + +#### Scenario: Implementation completion + +- **WHEN** all tasks are complete +- **THEN** agent announces completion +- **AND** summarizes what was done +- **AND** transitions to archive phase + +### Requirement: Archive with Explanation + +The skill SHALL archive the completed change and explain what happened. + +#### Scenario: Archive with narration + +- **WHEN** archiving the change +- **THEN** agent explains archive moves change to dated folder +- **AND** runs archive process +- **AND** shows where archived change lives +- **AND** explains the long-term value (finding decisions later) + +### Requirement: Recap and Next Steps + +The skill SHALL conclude with a recap and command reference. + +#### Scenario: Final recap + +- **WHEN** onboarding is complete +- **THEN** agent summarizes the workflow phases completed +- **AND** emphasizes this rhythm works for any size change +- **AND** provides command reference table (/opsx:explore, /opsx:new, /opsx:ff, /opsx:continue, /opsx:apply, /opsx:verify, /opsx:archive) +- **AND** suggests next actions (try /opsx:new or /opsx:ff on something) + +### Requirement: Graceful Exit Handling + +The skill SHALL handle users who want to stop mid-way. + +#### Scenario: User wants to stop + +- **WHEN** user indicates they want to stop during onboarding +- **THEN** agent acknowledges gracefully +- **AND** notes that the in-progress change is saved +- **AND** explains how to continue later with `/opsx:continue ` +- **AND** exits without pressure + +#### Scenario: User wants quick reference only + +- **WHEN** user says they just want to see the commands +- **THEN** agent provides command cheat sheet +- **AND** exits gracefully with encouragement to try `/opsx:new` diff --git a/openspec/changes/add-opsx-onboard-skill/tasks.md b/openspec/changes/add-opsx-onboard-skill/tasks.md new file mode 100644 index 000000000..7671b3291 --- /dev/null +++ b/openspec/changes/add-opsx-onboard-skill/tasks.md @@ -0,0 +1,21 @@ +## 1. Add Skill Template + +- [x] 1.1 Add `getOnboardSkillTemplate()` function to `src/core/templates/skill-templates.ts` with full onboarding instruction text covering all phases (preflight, welcome, task selection, explore demo, change creation, proposal, specs, design, tasks, apply, archive, recap) +- [x] 1.2 Include codebase analysis instructions for suggesting starter tasks (TODO/FIXME, missing error handling, missing tests, type:any, console.log, missing validation) +- [x] 1.3 Include narration pattern instructions (EXPLAIN → DO → SHOW → PAUSE at key transitions) +- [x] 1.4 Include scope guardrail instructions for redirecting users away from overly large tasks +- [x] 1.5 Include graceful exit handling instructions (user stops mid-way, user just wants command reference) + +## 2. Add Command Template + +- [x] 2.1 Add `getOpsxOnboardCommandTemplate()` function to `src/core/templates/skill-templates.ts` returning CommandTemplate with same instruction content as skill + +## 3. Register Templates + +- [x] 3.1 Add onboard skill to `getSkillTemplates()` array in `src/core/shared/skill-generation.ts` with dirName `openspec-onboard` +- [x] 3.2 Add onboard command to `getCommandTemplates()` array in `src/core/shared/skill-generation.ts` with id `onboard` + +## 4. Verify + +- [x] 4.1 Run `pnpm run build` to ensure TypeScript compiles +- [x] 4.2 Test skill generation by running `openspec init` in a test directory and verifying onboard skill/command files are created diff --git a/src/core/shared/skill-generation.ts b/src/core/shared/skill-generation.ts index c0119dc97..db7c6fe3c 100644 --- a/src/core/shared/skill-generation.ts +++ b/src/core/shared/skill-generation.ts @@ -14,6 +14,7 @@ import { getArchiveChangeSkillTemplate, getBulkArchiveChangeSkillTemplate, getVerifyChangeSkillTemplate, + getOnboardSkillTemplate, getOpsxExploreCommandTemplate, getOpsxNewCommandTemplate, getOpsxContinueCommandTemplate, @@ -23,6 +24,7 @@ import { getOpsxArchiveCommandTemplate, getOpsxBulkArchiveCommandTemplate, getOpsxVerifyCommandTemplate, + getOpsxOnboardCommandTemplate, type SkillTemplate, } from '../templates/skill-templates.js'; import type { CommandContent } from '../command-generation/index.js'; @@ -57,6 +59,7 @@ export function getSkillTemplates(): SkillTemplateEntry[] { { template: getArchiveChangeSkillTemplate(), dirName: 'openspec-archive-change' }, { template: getBulkArchiveChangeSkillTemplate(), dirName: 'openspec-bulk-archive-change' }, { template: getVerifyChangeSkillTemplate(), dirName: 'openspec-verify-change' }, + { template: getOnboardSkillTemplate(), dirName: 'openspec-onboard' }, ]; } @@ -74,6 +77,7 @@ export function getCommandTemplates(): CommandTemplateEntry[] { { template: getOpsxArchiveCommandTemplate(), id: 'archive' }, { template: getOpsxBulkArchiveCommandTemplate(), id: 'bulk-archive' }, { template: getOpsxVerifyCommandTemplate(), id: 'verify' }, + { template: getOpsxOnboardCommandTemplate(), id: 'onboard' }, ]; } diff --git a/src/core/templates/skill-templates.ts b/src/core/templates/skill-templates.ts index 811cdd3ab..8bae07359 100644 --- a/src/core/templates/skill-templates.ts +++ b/src/core/templates/skill-templates.ts @@ -920,6 +920,545 @@ Main specs are now updated. The change remains active - archive when implementat }; } +/** + * Template for openspec-onboard skill + * Guided onboarding through the complete OpenSpec workflow + */ +export function getOnboardSkillTemplate(): SkillTemplate { + return { + name: 'openspec-onboard', + description: 'Guided onboarding for OpenSpec - walk through a complete workflow cycle with narration and real codebase work.', + instructions: getOnboardInstructions(), + license: 'MIT', + compatibility: 'Requires openspec CLI.', + metadata: { author: 'openspec', version: '1.0' }, + }; +} + +/** + * Shared onboarding instructions used by both skill and command templates. + */ +function getOnboardInstructions(): string { + return `Guide the user through their first complete OpenSpec workflow cycle. This is a teaching experience—you'll do real work in their codebase while explaining each step. + +--- + +## Preflight + +Before starting, check if OpenSpec is initialized: + +\`\`\`bash +openspec status --json 2>&1 || echo "NOT_INITIALIZED" +\`\`\` + +**If not initialized:** +> OpenSpec isn't set up in this project yet. Run \`openspec init\` first, then come back to \`/opsx:onboard\`. + +Stop here if not initialized. + +--- + +## Phase 1: Welcome + +Display: + +\`\`\` +## Welcome to OpenSpec! + +I'll walk you through a complete change cycle—from idea to implementation—using a real task in your codebase. Along the way, you'll learn the workflow by doing it. + +**What we'll do:** +1. Pick a small, real task in your codebase +2. Explore the problem briefly +3. Create a change (the container for our work) +4. Build the artifacts: proposal → specs → design → tasks +5. Implement the tasks +6. Archive the completed change + +**Time:** ~15-20 minutes + +Let's start by finding something to work on. +\`\`\` + +--- + +## Phase 2: Task Selection + +### Codebase Analysis + +Scan the codebase for small improvement opportunities. Look for: + +1. **TODO/FIXME comments** - Search for \`TODO\`, \`FIXME\`, \`HACK\`, \`XXX\` in code files +2. **Missing error handling** - \`catch\` blocks that swallow errors, risky operations without try-catch +3. **Functions without tests** - Cross-reference \`src/\` with test directories +4. **Type issues** - \`any\` types in TypeScript files (\`: any\`, \`as any\`) +5. **Debug artifacts** - \`console.log\`, \`console.debug\`, \`debugger\` statements in non-debug code +6. **Missing validation** - User input handlers without validation + +Also check recent git activity: +\`\`\`bash +git log --oneline -10 2>/dev/null || echo "No git history" +\`\`\` + +### Present Suggestions + +From your analysis, present 3-4 specific suggestions: + +\`\`\` +## Task Suggestions + +Based on scanning your codebase, here are some good starter tasks: + +**1. [Most promising task]** + Location: \`src/path/to/file.ts:42\` + Scope: ~1-2 files, ~20-30 lines + Why it's good: [brief reason] + +**2. [Second task]** + Location: \`src/another/file.ts\` + Scope: ~1 file, ~15 lines + Why it's good: [brief reason] + +**3. [Third task]** + Location: [location] + Scope: [estimate] + Why it's good: [brief reason] + +**4. Something else?** + Tell me what you'd like to work on. + +Which task interests you? (Pick a number or describe your own) +\`\`\` + +**If nothing found:** Fall back to asking what the user wants to build: +> I didn't find obvious quick wins in your codebase. What's something small you've been meaning to add or fix? + +### Scope Guardrail + +If the user picks or describes something too large (major feature, multi-day work): + +\`\`\` +That's a valuable task, but it's probably larger than ideal for your first OpenSpec run-through. + +For learning the workflow, smaller is better—it lets you see the full cycle without getting stuck in implementation details. + +**Options:** +1. **Slice it smaller** - What's the smallest useful piece of [their task]? Maybe just [specific slice]? +2. **Pick something else** - One of the other suggestions, or a different small task? +3. **Do it anyway** - If you really want to tackle this, we can. Just know it'll take longer. + +What would you prefer? +\`\`\` + +Let the user override if they insist—this is a soft guardrail. + +--- + +## Phase 3: Explore Demo + +Once a task is selected, briefly demonstrate explore mode: + +\`\`\` +Before we create a change, let me quickly show you **explore mode**—it's how you think through problems before committing to a direction. +\`\`\` + +Spend 1-2 minutes investigating the relevant code: +- Read the file(s) involved +- Draw a quick ASCII diagram if it helps +- Note any considerations + +\`\`\` +## Quick Exploration + +[Your brief analysis—what you found, any considerations] + +┌─────────────────────────────────────────┐ +│ [Optional: ASCII diagram if helpful] │ +└─────────────────────────────────────────┘ + +Explore mode (\`/opsx:explore\`) is for this kind of thinking—investigating before implementing. You can use it anytime you need to think through a problem. + +Now let's create a change to hold our work. +\`\`\` + +**PAUSE** - Wait for user acknowledgment before proceeding. + +--- + +## Phase 4: Create the Change + +**EXPLAIN:** +\`\`\` +## Creating a Change + +A "change" in OpenSpec is a container for all the thinking and planning around a piece of work. It lives in \`openspec/changes//\` and holds your artifacts—proposal, specs, design, tasks. + +Let me create one for our task. +\`\`\` + +**DO:** Create the change with a derived kebab-case name: +\`\`\`bash +openspec new change "" +\`\`\` + +**SHOW:** +\`\`\` +Created: \`openspec/changes//\` + +The folder structure: +\`\`\` +openspec/changes// +├── proposal.md ← Why we're doing this (empty, we'll fill it) +├── design.md ← How we'll build it (empty) +├── specs/ ← Detailed requirements (empty) +└── tasks.md ← Implementation checklist (empty) +\`\`\` + +Now let's fill in the first artifact—the proposal. +\`\`\` + +--- + +## Phase 5: Proposal + +**EXPLAIN:** +\`\`\` +## The Proposal + +The proposal captures **why** we're making this change and **what** it involves at a high level. It's the "elevator pitch" for the work. + +I'll draft one based on our task. +\`\`\` + +**DO:** Draft the proposal content (don't save yet): + +\`\`\` +Here's a draft proposal: + +--- + +## Why + +[1-2 sentences explaining the problem/opportunity] + +## What Changes + +[Bullet points of what will be different] + +## Capabilities + +### New Capabilities +- \`\`: [brief description] + +### Modified Capabilities + + +## Impact + +- \`src/path/to/file.ts\`: [what changes] +- [other files if applicable] + +--- + +Does this capture the intent? I can adjust before we save it. +\`\`\` + +**PAUSE** - Wait for user approval/feedback. + +After approval, save the proposal: +\`\`\`bash +openspec instructions proposal --change "" --json +\`\`\` +Then write the content to \`openspec/changes//proposal.md\`. + +\`\`\` +Proposal saved. This is your "why" document—you can always come back and refine it as understanding evolves. + +Next up: specs. +\`\`\` + +--- + +## Phase 6: Specs + +**EXPLAIN:** +\`\`\` +## Specs + +Specs define **what** we're building in precise, testable terms. They use a requirement/scenario format that makes expected behavior crystal clear. + +For a small task like this, we might only need one spec file. +\`\`\` + +**DO:** Create the spec file: +\`\`\`bash +mkdir -p openspec/changes//specs/ +\`\`\` + +Draft the spec content: + +\`\`\` +Here's the spec: + +--- + +## ADDED Requirements + +### Requirement: + + + +#### Scenario: + +- **WHEN** +- **THEN** +- **AND** + +--- + +This format—WHEN/THEN/AND—makes requirements testable. You can literally read them as test cases. +\`\`\` + +Save to \`openspec/changes//specs//spec.md\`. + +--- + +## Phase 7: Design + +**EXPLAIN:** +\`\`\` +## Design + +The design captures **how** we'll build it—technical decisions, tradeoffs, approach. + +For small changes, this might be brief. That's fine—not every change needs deep design discussion. +\`\`\` + +**DO:** Draft design.md: + +\`\`\` +Here's the design: + +--- + +## Context + +[Brief context about the current state] + +## Goals / Non-Goals + +**Goals:** +- [What we're trying to achieve] + +**Non-Goals:** +- [What's explicitly out of scope] + +## Decisions + +### Decision 1: [Key decision] + +[Explanation of approach and rationale] + +--- + +For a small task, this captures the key decisions without over-engineering. +\`\`\` + +Save to \`openspec/changes//design.md\`. + +--- + +## Phase 8: Tasks + +**EXPLAIN:** +\`\`\` +## Tasks + +Finally, we break the work into implementation tasks—checkboxes that drive the apply phase. + +These should be small, clear, and in logical order. +\`\`\` + +**DO:** Generate tasks based on specs and design: + +\`\`\` +Here are the implementation tasks: + +--- + +## 1. [Category or file] + +- [ ] 1.1 [Specific task] +- [ ] 1.2 [Specific task] + +## 2. Verify + +- [ ] 2.1 [Verification step] + +--- + +Each checkbox becomes a unit of work in the apply phase. Ready to implement? +\`\`\` + +**PAUSE** - Wait for user to confirm they're ready to implement. + +Save to \`openspec/changes//tasks.md\`. + +--- + +## Phase 9: Apply (Implementation) + +**EXPLAIN:** +\`\`\` +## Implementation + +Now we implement each task, checking them off as we go. I'll announce each one and occasionally note how the specs/design informed the approach. +\`\`\` + +**DO:** For each task: + +1. Announce: "Working on task N: [description]" +2. Implement the change in the codebase +3. Reference specs/design naturally: "The spec says X, so I'm doing Y" +4. Mark complete in tasks.md: \`- [ ]\` → \`- [x]\` +5. Brief status: "✓ Task N complete" + +Keep narration light—don't over-explain every line of code. + +After all tasks: + +\`\`\` +## Implementation Complete + +All tasks done: +- [x] Task 1 +- [x] Task 2 +- [x] ... + +The change is implemented! One more step—let's archive it. +\`\`\` + +--- + +## Phase 10: Archive + +**EXPLAIN:** +\`\`\` +## Archiving + +When a change is complete, we archive it. This moves it from \`openspec/changes/\` to \`openspec/archive/YYYY-MM-DD--/\`. + +Archived changes become your project's decision history—you can always find them later to understand why something was built a certain way. +\`\`\` + +**DO:** +\`\`\`bash +openspec archive "" +\`\`\` + +**SHOW:** +\`\`\` +Archived to: \`openspec/archive/YYYY-MM-DD--/\` + +The change is now part of your project's history. The code is in your codebase, the decision record is preserved. +\`\`\` + +--- + +## Phase 11: Recap & Next Steps + +\`\`\` +## Congratulations! + +You just completed a full OpenSpec cycle: + +1. **Explore** - Thought through the problem +2. **New** - Created a change container +3. **Proposal** - Captured WHY +4. **Specs** - Defined WHAT in detail +5. **Design** - Decided HOW +6. **Tasks** - Broke it into steps +7. **Apply** - Implemented the work +8. **Archive** - Preserved the record + +This same rhythm works for any size change—a small fix or a major feature. + +--- + +## Command Reference + +| Command | What it does | +|---------|--------------| +| \`/opsx:explore\` | Think through problems before/during work | +| \`/opsx:new\` | Start a new change, step through artifacts | +| \`/opsx:ff\` | Fast-forward: create all artifacts at once | +| \`/opsx:continue\` | Continue working on an existing change | +| \`/opsx:apply\` | Implement tasks from a change | +| \`/opsx:verify\` | Verify implementation matches artifacts | +| \`/opsx:archive\` | Archive a completed change | + +--- + +## What's Next? + +Try \`/opsx:new\` or \`/opsx:ff\` on something you actually want to build. You've got the rhythm now! +\`\`\` + +--- + +## Graceful Exit Handling + +### User wants to stop mid-way + +If the user says they need to stop, want to pause, or seem disengaged: + +\`\`\` +No problem! Your change is saved at \`openspec/changes//\`. + +To pick up where we left off later: +- \`/opsx:continue \` - Resume artifact creation +- \`/opsx:apply \` - Jump to implementation (if tasks exist) + +The work won't be lost. Come back whenever you're ready. +\`\`\` + +Exit gracefully without pressure. + +### User just wants command reference + +If the user says they just want to see the commands or skip the tutorial: + +\`\`\` +## OpenSpec Quick Reference + +| Command | What it does | +|---------|--------------| +| \`/opsx:explore\` | Think through problems (no code changes) | +| \`/opsx:new \` | Start a new change, step by step | +| \`/opsx:ff \` | Fast-forward: all artifacts at once | +| \`/opsx:continue \` | Continue an existing change | +| \`/opsx:apply \` | Implement tasks | +| \`/opsx:verify \` | Verify implementation | +| \`/opsx:archive \` | Archive when done | + +Try \`/opsx:new\` to start your first change, or \`/opsx:ff\` if you want to move fast. +\`\`\` + +Exit gracefully. + +--- + +## Guardrails + +- **Follow the EXPLAIN → DO → SHOW → PAUSE pattern** at key transitions (after explore, after proposal draft, after tasks, after archive) +- **Keep narration light** during implementation—teach without lecturing +- **Don't skip phases** even if the change is small—the goal is teaching the workflow +- **Pause for acknowledgment** at marked points, but don't over-pause +- **Handle exits gracefully**—never pressure the user to continue +- **Use real codebase tasks**—don't simulate or use fake examples +- **Adjust scope gently**—guide toward smaller tasks but respect user choice`; +} + // ----------------------------------------------------------------------------- // Slash Command Templates // ----------------------------------------------------------------------------- @@ -2408,6 +2947,20 @@ Target archive directory already exists. }; } +/** + * Template for /opsx:onboard slash command + * Guided onboarding through the complete OpenSpec workflow + */ +export function getOpsxOnboardCommandTemplate(): CommandTemplate { + return { + name: 'OPSX: Onboard', + description: 'Guided onboarding - walk through a complete OpenSpec workflow cycle with narration', + category: 'Workflow', + tags: ['workflow', 'onboarding', 'tutorial', 'learning'], + content: getOnboardInstructions(), + }; +} + /** * Template for /opsx:bulk-archive slash command */ From fabb9160ebd4947abb12f8c4ba361d08553df88c Mon Sep 17 00:00:00 2001 From: Tabish Bidiwale Date: Sat, 24 Jan 2026 14:55:13 -0800 Subject: [PATCH 02/14] test(skills): update skill-generation tests for onboard skill Update test expectations from 9 to 10 skills after adding opsx:onboard. --- test/core/shared/skill-generation.test.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/core/shared/skill-generation.test.ts b/test/core/shared/skill-generation.test.ts index f69cfaa43..df6d2e3b8 100644 --- a/test/core/shared/skill-generation.test.ts +++ b/test/core/shared/skill-generation.test.ts @@ -8,9 +8,9 @@ import { describe('skill-generation', () => { describe('getSkillTemplates', () => { - it('should return all 9 skill templates', () => { + it('should return all 10 skill templates', () => { const templates = getSkillTemplates(); - expect(templates).toHaveLength(9); + expect(templates).toHaveLength(10); }); it('should have unique directory names', () => { @@ -33,6 +33,7 @@ describe('skill-generation', () => { expect(dirNames).toContain('openspec-archive-change'); expect(dirNames).toContain('openspec-bulk-archive-change'); expect(dirNames).toContain('openspec-verify-change'); + expect(dirNames).toContain('openspec-onboard'); }); it('should have valid template structure', () => { @@ -48,9 +49,9 @@ describe('skill-generation', () => { }); describe('getCommandTemplates', () => { - it('should return all 9 command templates', () => { + it('should return all 10 command templates', () => { const templates = getCommandTemplates(); - expect(templates).toHaveLength(9); + expect(templates).toHaveLength(10); }); it('should have unique IDs', () => { @@ -73,13 +74,14 @@ describe('skill-generation', () => { expect(ids).toContain('archive'); expect(ids).toContain('bulk-archive'); expect(ids).toContain('verify'); + expect(ids).toContain('onboard'); }); }); describe('getCommandContents', () => { - it('should return all 9 command contents', () => { + it('should return all 10 command contents', () => { const contents = getCommandContents(); - expect(contents).toHaveLength(9); + expect(contents).toHaveLength(10); }); it('should have valid content structure', () => { From 52c9dfa3354bd253799a5755e26e7da6fdf01b1e Mon Sep 17 00:00:00 2001 From: Tabish Bidiwale Date: Sat, 24 Jan 2026 16:19:20 -0800 Subject: [PATCH 03/14] docs: update README links and add doc cleanup checklist - Replace placeholder links in README_NEW.md with actual doc paths - Add documentation cleanup checklist to README_RENEWAL_PROMPTS.md --- README_NEW.md | 18 ++++++++--------- docs/README_RENEWAL_PROMPTS.md | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/README_NEW.md b/README_NEW.md index ecbc48047..22440f6d5 100644 --- a/README_NEW.md +++ b/README_NEW.md @@ -86,20 +86,20 @@ openspec init Now tell your AI: `/opsx:new ` > [!NOTE] -> Not sure if your tool is supported? [View the full list](link) – we support 20+ tools and growing. +> Not sure if your tool is supported? [View the full list](docs/getting-started.md#supported-tools) – we support 20+ tools and growing. > [!NOTE] -> Also works with pnpm, yarn, bun, and nix. [See installation options](link). +> Also works with pnpm, yarn, bun, and nix. [See installation options](docs/cli.md#installation). ## Docs -→ **[Getting Started](link)**: first steps
-→ **[Workflows](link)**: combo's and patterns
-→ **[Commands](link)**: slash commands & skills
-→ **[CLI](link)**: terminal reference
-→ **[Concepts](link)**: how it all fits
-→ **[i18n](link)**: multi-language support
-→ **[Customization](link)**: make it yours +→ **[Getting Started](docs/getting-started.md)**: first steps
+→ **[Workflows](docs/workflows.md)**: combo's and patterns
+→ **[Commands](docs/commands.md)**: slash commands & skills
+→ **[CLI](docs/cli.md)**: terminal reference
+→ **[Concepts](docs/concepts.md)**: how it all fits
+→ **[i18n](docs/i18n.md)**: multi-language support
+→ **[Customization](docs/customization.md)**: make it yours ## Why OpenSpec? diff --git a/docs/README_RENEWAL_PROMPTS.md b/docs/README_RENEWAL_PROMPTS.md index 52a53b846..92ec8f8a3 100644 --- a/docs/README_RENEWAL_PROMPTS.md +++ b/docs/README_RENEWAL_PROMPTS.md @@ -4,6 +4,43 @@ This file contains prompts for AI agents to write each documentation file. Each --- +## Documentation Cleanup Checklist + +Before generating new docs, clean up the existing docs folder. + +### Docs to Delete (internal/historical) + +- [ ] `docs/artifact_poc.md` — Internal architecture doc, design decisions implemented +- [ ] `docs/experimental-release-plan.md` — Project plan with completed checkboxes, release happened +- [ ] `docs/schema-workflow-gaps.md` — Implementation tracking (Phases 1-4), belongs in GitHub issues + +### Docs to Merge Then Delete + +- [ ] `docs/schema-customization.md` → merge useful content into `docs/customization.md`, then delete +- [ ] `docs/project-config-demo.md` → merge useful content into `docs/customization.md`, then delete + +### Docs to Keep and Polish + +- [ ] `docs/experimental-workflow.md` — Core OPSX user documentation (consider renaming to `opsx.md`) + +### User-Facing Docs to Generate/Update + +- [ ] `docs/getting-started.md` — See prompt below +- [ ] `docs/workflows.md` — See prompt below +- [ ] `docs/commands.md` — See prompt below +- [ ] `docs/cli.md` — See prompt below +- [ ] `docs/concepts.md` — See prompt below +- [ ] `docs/i18n.md` — See prompt below +- [ ] `docs/customization.md` — See prompt below (include content from schema-customization.md and project-config-demo.md) + +### Final Steps + +- [ ] Delete this file (`README_RENEWAL_PROMPTS.md`) after all docs are generated +- [ ] Update `README_NEW.md` links to point to new docs +- [ ] Rename `README_NEW.md` to `README.md` (replace old README) + +--- + ## 1. Getting Started (`docs/getting-started.md`) ``` From c7e60b5db2695fd5dc2f0c67e94302388e767678 Mon Sep 17 00:00:00 2001 From: Tabish Bidiwale Date: Sat, 24 Jan 2026 18:17:57 -0800 Subject: [PATCH 04/14] docs: overhaul documentation with new workflows, getting-started, and customization guides - Rewrite workflows.md with action-based philosophy and workflow patterns - Rewrite getting-started.md with clearer onboarding flow - Rewrite customization.md with schema customization guidance - Add cross-references between docs (Commands, Customization links) - Remove obsolete docs: artifact_poc, experimental-release-plan, project-config-demo, schema-customization, schema-workflow-gaps - Update README_RENEWAL_PROMPTS.md checklist --- docs/README_RENEWAL_PROMPTS.md | 16 +- docs/artifact_poc.md | 597 ------------------- docs/customization.md | 182 ++++++ docs/experimental-release-plan.md | 926 ------------------------------ docs/getting-started.md | 273 +++++++++ docs/project-config-demo.md | 205 ------- docs/schema-customization.md | 211 ------- docs/schema-workflow-gaps.md | 379 ------------ docs/workflows.md | 520 +++++++++++++++++ 9 files changed, 983 insertions(+), 2326 deletions(-) delete mode 100644 docs/artifact_poc.md delete mode 100644 docs/experimental-release-plan.md delete mode 100644 docs/project-config-demo.md delete mode 100644 docs/schema-customization.md delete mode 100644 docs/schema-workflow-gaps.md diff --git a/docs/README_RENEWAL_PROMPTS.md b/docs/README_RENEWAL_PROMPTS.md index 92ec8f8a3..6d084aa34 100644 --- a/docs/README_RENEWAL_PROMPTS.md +++ b/docs/README_RENEWAL_PROMPTS.md @@ -10,14 +10,14 @@ Before generating new docs, clean up the existing docs folder. ### Docs to Delete (internal/historical) -- [ ] `docs/artifact_poc.md` — Internal architecture doc, design decisions implemented -- [ ] `docs/experimental-release-plan.md` — Project plan with completed checkboxes, release happened -- [ ] `docs/schema-workflow-gaps.md` — Implementation tracking (Phases 1-4), belongs in GitHub issues +- [x] `docs/artifact_poc.md` — Internal architecture doc, design decisions implemented +- [x] `docs/experimental-release-plan.md` — Project plan with completed checkboxes, release happened +- [x] `docs/schema-workflow-gaps.md` — Implementation tracking (Phases 1-4), belongs in GitHub issues ### Docs to Merge Then Delete -- [ ] `docs/schema-customization.md` → merge useful content into `docs/customization.md`, then delete -- [ ] `docs/project-config-demo.md` → merge useful content into `docs/customization.md`, then delete +- [x] `docs/schema-customization.md` → merge useful content into `docs/customization.md`, then delete +- [x] `docs/project-config-demo.md` → merge useful content into `docs/customization.md`, then delete ### Docs to Keep and Polish @@ -25,13 +25,13 @@ Before generating new docs, clean up the existing docs folder. ### User-Facing Docs to Generate/Update -- [ ] `docs/getting-started.md` — See prompt below -- [ ] `docs/workflows.md` — See prompt below +- [x] `docs/getting-started.md` — See prompt below +- [x] `docs/workflows.md` — See prompt below - [ ] `docs/commands.md` — See prompt below - [ ] `docs/cli.md` — See prompt below - [ ] `docs/concepts.md` — See prompt below - [ ] `docs/i18n.md` — See prompt below -- [ ] `docs/customization.md` — See prompt below (include content from schema-customization.md and project-config-demo.md) +- [x] `docs/customization.md` — Merged from schema-customization.md and project-config-demo.md ### Final Steps diff --git a/docs/artifact_poc.md b/docs/artifact_poc.md deleted file mode 100644 index 01dd00985..000000000 --- a/docs/artifact_poc.md +++ /dev/null @@ -1,597 +0,0 @@ -# POC-OpenSpec-Core Analysis - ---- - -## Design Decisions & Terminology - -### Philosophy: Not a Workflow System - -This system is **not** a workflow engine. It's an **artifact tracker with dependency awareness**. - -| What it's NOT | What it IS | -|---------------|------------| -| Linear step-by-step progression | Exploratory, iterative planning | -| Bureaucratic checkpoints | Enablers that unlock possibilities | -| "You must complete step 1 first" | "Here's what you could create now" | -| Form-filling | Fluid document creation | - -**Key insight:** Dependencies are *enablers*, not *gates*. You can't meaningfully write a design document if there's no proposal to design from - that's not bureaucracy, it's logic. - -### Terminology - -| Term | Definition | Example | -|------|------------|---------| -| **Change** | A unit of work being planned (feature, refactor, migration) | `openspec/changes/add-auth/` | -| **Schema** | An artifact graph definition (what artifacts exist, their dependencies) | `spec-driven.yaml` | -| **Artifact** | A node in the graph (a document to create) | `proposal`, `design`, `specs` | -| **Template** | Instructions/guidance for creating an artifact | `templates/proposal.md` | - -### Hierarchy - -``` -Schema (defines) ──→ Artifacts (guided by) ──→ Templates -``` - -- **Schema** = the artifact graph (what exists, dependencies) -- **Artifact** = a document to produce -- **Template** = instructions for creating that artifact - -### Schema Variations - -Schemas can vary across multiple dimensions: - -| Dimension | Examples | -|-----------|----------| -| Philosophy | `spec-driven`, `tdd`, `prototype-first` | -| Version | `v1`, `v2`, `v3` | -| Language | `en`, `zh`, `es` | -| Custom | `team-alpha`, `experimental` | - -### Schema Resolution (XDG Standard) - -Schemas follow the XDG Base Directory Specification with a 2-level resolution: - -``` -1. ${XDG_DATA_HOME}/openspec/schemas//schema.yaml # Global user override -2. /schemas//schema.yaml # Built-in defaults -``` - -**Platform-specific paths:** -- Unix/macOS: `~/.local/share/openspec/schemas/` -- Windows: `%LOCALAPPDATA%/openspec/schemas/` -- All platforms: `$XDG_DATA_HOME/openspec/schemas/` (when set) - -**Why XDG?** -- Schemas are workflow definitions (data), not user preferences (config) -- Built-ins baked into package, never auto-copied -- Users customize by creating files in global data dir -- Consistent with modern CLI tooling standards - -### Template Inheritance (2 Levels Max) - -Templates are co-located with schemas in a `templates/` subdirectory: - -``` -1. ${XDG_DATA_HOME}/openspec/schemas//templates/.md # User override -2. /schemas//templates/.md # Built-in -``` - -**Rules:** -- User overrides take precedence over package built-ins -- A CLI command shows resolved paths (no guessing) -- No inheritance between schemas (copy if you need to diverge) -- Templates are always co-located with their schema - -**Why this matters:** -- Avoids "where does this come from?" debugging -- No implicit magic that works until it doesn't -- Schema + templates form a cohesive unit - ---- - -## Executive Summary - -This is an **artifact tracker with dependency awareness** that guides iterative development through a structured artifact pipeline. The core innovation is using the **filesystem as a database** - artifact completion is detected by file existence, making the system stateless and version-control friendly. - -The system answers: -- "What artifacts exist for this change?" -- "What could I create next?" (not "what must I create") -- "What's blocking X?" (informational, not prescriptive) - ---- - -## Core Components - -### 1. ArtifactGraph (Slice 1 - COMPLETE) - -The dependency graph engine with XDG-compliant schema resolution. - -| Responsibility | Approach | -|----------------|----------| -| Model artifacts as a DAG | Artifact with `requires: string[]` | -| Track completion state | `Set` for completed artifacts | -| Calculate build order | Kahn's algorithm (topological sort) | -| Find ready artifacts | Check if all dependencies are in `completed` set | -| Resolve schemas | XDG global → package built-ins | - -**Key Data Structures (Zod-validated):** - -```typescript -// Zod schemas define types + validation -const ArtifactSchema = z.object({ - id: z.string().min(1), - generates: z.string().min(1), // e.g., "proposal.md" or "specs/*.md" - description: z.string(), - template: z.string(), // path to template file - requires: z.array(z.string()).default([]), -}); - -const SchemaYamlSchema = z.object({ - name: z.string().min(1), - version: z.number().int().positive(), - description: z.string().optional(), - artifacts: z.array(ArtifactSchema).min(1), -}); - -// Derived types -type Artifact = z.infer; -type SchemaYaml = z.infer; -``` - -**Key Methods:** -- `resolveSchema(name)` - Load schema with XDG fallback -- `ArtifactGraph.fromSchema(schema)` - Build graph from schema -- `detectState(graph, changeDir)` - Scan filesystem for completion -- `getNextArtifacts(graph, completed)` - Find artifacts ready to create -- `getBuildOrder(graph)` - Topological sort of all artifacts -- `getBlocked(graph, completed)` - Artifacts with unmet dependencies - ---- - -### 2. Change Utilities (Slice 2) - -Simple utility functions for programmatic change creation. No class, no abstraction layer. - -| Responsibility | Approach | -|----------------|----------| -| Create changes | Create dirs under `openspec/changes//` with README | -| Name validation | Enforce kebab-case naming | - -**Key Paths:** - -``` -openspec/changes// → Change instances with artifacts (project-level) -``` - -**Key Functions** (`src/utils/change-utils.ts`): -- `createChange(projectRoot, name, description?)` - Create new change directory + README -- `validateChangeName(name)` - Validate kebab-case naming, returns `{ valid, error? }` - -**Note:** Existing CLI commands (`ListCommand`, `ChangeCommand`) already handle listing, path resolution, and existence checks. No need to extract that logic - it works fine as-is. - ---- - -### 3. InstructionLoader (Slice 3) - -Template resolution and instruction enrichment. - -| Responsibility | Approach | -|----------------|----------| -| Resolve templates | XDG 2-level fallback (schema-specific → shared → built-in) | -| Build dynamic context | Gather dependency status, change info | -| Enrich templates | Inject context into base templates | -| Generate status reports | Formatted markdown with progress | - -**Key Class - ChangeState:** - -``` -ChangeState { - changeName: string - changeDir: string - graph: ArtifactGraph - completed: Set - - // Methods - getNextSteps(): string[] - getStatus(artifactId): ArtifactStatus - isComplete(): boolean -} -``` - -**Key Functions:** -- `getTemplatePath(artifactId, schemaName?)` - Resolve with 2-level fallback -- `getEnrichedInstructions(artifactId, projectRoot, changeName?)` - Main entry point -- `getChangeStatus(projectRoot, changeName?)` - Formatted status report - ---- - -### 4. CLI (Slice 4) - -User interface layer. **All commands are deterministic** - require explicit `--change` parameter. - -| Command | Function | Status | -|---------|----------|--------| -| `status --change ` | Show change progress (artifact graph) | **NEW** | -| `next --change ` | Show artifacts ready to create | **NEW** | -| `instructions --change ` | Get enriched instructions for artifact | **NEW** | -| `list` | List all changes | EXISTS (`openspec change list`) | -| `new ` | Create change | **NEW** (uses `createChange()`) | -| `init` | Initialize structure | EXISTS (`openspec init`) | -| `templates --change ` | Show resolved template paths | **NEW** | - -**Note:** Commands that operate on a change require `--change`. Missing parameter → error with list of available changes. Agent infers the change from conversation and passes it explicitly. - -**Existing CLI commands** (not part of this slice): -- `openspec change list` / `openspec change show ` / `openspec change validate ` -- `openspec list --changes` / `openspec list --specs` -- `openspec view` (dashboard) -- `openspec init` / `openspec archive ` - ---- - -### 5. Claude Commands - -Integration layer for Claude Code. **Operational commands only** - artifact creation via natural language. - -| Command | Purpose | -|---------|---------| -| `/status` | Show change progress | -| `/next` | Show what's ready to create | -| `/run [artifact]` | Execute a specific step (power users) | -| `/list` | List all changes | -| `/new ` | Create a new change | -| `/init` | Initialize structure | - -**Artifact creation:** Users say "create the proposal" or "write the tests" in natural language. The agent: -1. Infers change from conversation (confirms if uncertain) -2. Infers artifact from request -3. Calls CLI with explicit `--change` parameter -4. Creates artifact following instructions - -This works for ANY artifact in ANY schema - no new slash commands needed when schemas change. - -**Note:** Legacy commands (`/openspec-proposal`, `/openspec-apply`, `/openspec-archive`) exist in the main project for backward compatibility but are separate from this architecture. - ---- - -## Component Dependency Graph - -``` -┌─────────────────────────────────────────────────────────────┐ -│ PRESENTATION LAYER │ -│ ┌──────────────┐ ┌────────────────────┐ │ -│ │ CLI │ ←─shell exec───────│ Claude Commands │ │ -│ └──────┬───────┘ └────────────────────┘ │ -└─────────┼───────────────────────────────────────────────────┘ - │ imports - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ ORCHESTRATION LAYER │ -│ ┌────────────────────┐ ┌──────────────────────────┐ │ -│ │ InstructionLoader │ │ change-utils (Slice 2) │ │ -│ │ (Slice 3) │ │ createChange() │ │ -│ └─────────┬──────────┘ │ validateChangeName() │ │ -│ │ └──────────────────────────┘ │ -└────────────┼────────────────────────────────────────────────┘ - │ uses - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ CORE LAYER │ -│ ┌──────────────────────────────────────────────────────┐ │ -│ │ ArtifactGraph (Slice 1) │ │ -│ │ │ │ -│ │ Schema Resolution (XDG) ──→ Graph ──→ State Detection│ │ -│ └──────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ - ▲ - │ reads from - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ PERSISTENCE LAYER │ -│ ┌──────────────────┐ ┌────────────────────────────────┐ │ -│ │ XDG Schemas │ │ Project Artifacts │ │ -│ │ ~/.local/share/ │ │ openspec/changes// │ │ -│ │ openspec/ │ │ - proposal.md, design.md │ │ -│ │ schemas/ │ │ - specs/*.md, tasks.md │ │ -│ └──────────────────┘ └────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ -``` - ---- - -## Key Design Patterns - -### 1. Filesystem as Database - -No SQLite, no JSON state files. The existence of `proposal.md` means proposal is complete. - -``` -// State detection is just file existence checking -if (exists(artifactPath)) { - completed.add(artifactId) -} -``` - -### 2. Deterministic CLI, Inferring Agent - -**CLI layer:** Always deterministic - requires explicit `--change` parameter. - -``` -openspec status --change add-auth # explicit, works -openspec status # error: "No change specified" -``` - -**Agent layer:** Infers from conversation, confirms if uncertain, passes explicit `--change`. - -This separation means: -- CLI is pure, testable, no state to corrupt -- Agent handles all "smartness" -- No config.yaml tracking of "active change" - -### 3. XDG-Compliant Schema Resolution - -``` -${XDG_DATA_HOME}/openspec/schemas//schema.yaml # User override - ↓ (not found) -/schemas//schema.yaml # Built-in - ↓ (not found) -Error (schema not found) -``` - -### 4. Two-Level Template Fallback - -``` -${XDG_DATA_HOME}/openspec/schemas//templates/.md # User override - ↓ (not found) -/schemas//templates/.md # Built-in - ↓ (not found) -Error (no silent fallback to avoid confusion) -``` - -### 5. Glob Pattern Support - -`specs/*.md` allows multiple files to satisfy a single artifact: - -``` -if (artifact.generates.includes("*")) { - const parentDir = changeDir / patternParts[0] - if (exists(parentDir) && hasFiles(parentDir)) { - completed.add(artifactId) - } -} -``` - -### 6. Stateless State Detection - -Every command re-scans the filesystem. No cached state to corrupt. - ---- - -## Artifact Pipeline (Default Schema) - -The default `spec-driven` schema: - -``` -┌──────────┐ -│ proposal │ (no dependencies) -└────┬─────┘ - │ - ▼ -┌──────────┐ -│ specs │ (requires: proposal) -└────┬─────┘ - │ - ├──────────────┐ - ▼ ▼ -┌──────────┐ ┌──────────┐ -│ design │ │ │ -│ │◄──┤ proposal │ -└────┬─────┘ └──────────┘ - │ (requires: proposal, specs) - ▼ -┌──────────┐ -│ tasks │ (requires: design) -└──────────┘ -``` - -Other schemas (TDD, prototype-first) would have different graphs. - ---- - -## Implementation Order - -Structured as **vertical slices** - each slice is independently testable. - ---- - -### Slice 1: "What's Ready?" (Core Query) ✅ COMPLETE - -**Delivers:** Types + Graph + State Detection + Schema Resolution - -**Implementation:** `src/core/artifact-graph/` -- `types.ts` - Zod schemas and derived TypeScript types -- `schema.ts` - YAML parsing with Zod validation -- `graph.ts` - ArtifactGraph class with topological sort -- `state.ts` - Filesystem-based state detection -- `resolver.ts` - XDG-compliant schema resolution -- `builtin-schemas.ts` - Package-bundled default schemas - -**Key decisions made:** -- Zod for schema validation (consistent with project) -- XDG for global schema overrides -- `Set` for completion state (immutable, functional) -- `inProgress` and `failed` states deferred (require external tracking) - ---- - -### Slice 2: "Change Creation Utilities" - -**Delivers:** Utility functions for programmatic change creation - -**Scope:** -- `createChange(projectRoot, name, description?)` → creates directory + README -- `validateChangeName(name)` → kebab-case pattern enforcement - -**Not in scope (already exists in CLI commands):** -- `listChanges()` → exists in `ListCommand` and `ChangeCommand.getActiveChanges()` -- `getChangePath()` → simple `path.join()` inline -- `changeExists()` → simple `fs.access()` inline -- `isInitialized()` → simple directory check inline - -**Why simplified:** Extracting existing CLI logic into a class would require similar refactoring of `SpecCommand` for consistency. The existing code works fine (~15 lines each). Only truly new functionality is `createChange()` + name validation. - ---- - -### Slice 3: "Get Instructions" (Enrichment) - -**Delivers:** Template resolution + context injection - -**Testable behaviors:** -- Template fallback: schema-specific → shared → built-in → error -- Context injection: completed deps show ✓, missing show ✗ -- Output path shown correctly based on change directory - ---- - -### Slice 4: "CLI + Integration" - -**Delivers:** New artifact graph commands (builds on existing CLI) - -**New commands:** -- `status --change ` - Show artifact completion state -- `next --change ` - Show ready-to-create artifacts -- `instructions --change ` - Get enriched template -- `templates --change ` - Show resolved paths -- `new ` - Create change (wrapper for `createChange()`) - -**Already exists (not in scope):** -- `openspec change list/show/validate` - change management -- `openspec list --changes/--specs` - listing -- `openspec view` - dashboard -- `openspec init` - initialization - -**Testable behaviors:** -- Each new command produces expected output -- Commands compose correctly (status → next → instructions flow) -- Error handling for missing changes, invalid artifacts, etc. - ---- - -## Directory Structure - -``` -# Global (XDG paths - user overrides) -~/.local/share/openspec/ # Unix/macOS ($XDG_DATA_HOME/openspec/) -%LOCALAPPDATA%/openspec/ # Windows -└── schemas/ # Schema overrides - └── custom-workflow/ # User-defined schema directory - ├── schema.yaml # Schema definition - └── templates/ # Co-located templates - └── proposal.md - -# Package (built-in defaults) -/ -└── schemas/ # Built-in schema definitions - ├── spec-driven/ # Default: proposal → specs → design → tasks - │ ├── schema.yaml - │ └── templates/ - │ ├── proposal.md - │ ├── design.md - │ ├── spec.md - │ └── tasks.md - └── tdd/ # TDD: tests → implementation → docs - ├── schema.yaml - └── templates/ - ├── test.md - ├── implementation.md - ├── spec.md - └── docs.md - -# Project (change instances) -openspec/ -└── changes/ # Change instances - ├── add-auth/ - │ ├── README.md # Auto-generated on creation - │ ├── proposal.md # Created artifacts - │ ├── design.md - │ └── specs/ - │ └── *.md - ├── refactor-db/ - │ └── ... - └── archive/ # Completed changes - └── 2025-01-01-add-auth/ - -.claude/ -├── settings.local.json # Permissions -└── commands/ # Slash commands - └── *.md -``` - ---- - -## Schema YAML Format - -```yaml -# Built-in: /schemas/spec-driven/schema.yaml -# Or user override: ~/.local/share/openspec/schemas/spec-driven/schema.yaml -name: spec-driven -version: 1 -description: Specification-driven development - -artifacts: - - id: proposal - generates: "proposal.md" - description: "Create project proposal document" - template: "proposal.md" # resolves from co-located templates/ directory - requires: [] - - - id: specs - generates: "specs/*.md" # glob pattern - description: "Create technical specification documents" - template: "specs.md" - requires: - - proposal - - - id: design - generates: "design.md" - description: "Create design document" - template: "design.md" - requires: - - proposal - - specs - - - id: tasks - generates: "tasks.md" - description: "Create tasks breakdown document" - template: "tasks.md" - requires: - - design -``` - ---- - -## Summary - -| Layer | Component | Responsibility | Status | -|-------|-----------|----------------|--------| -| Core | ArtifactGraph | Pure dependency logic + XDG schema resolution | ✅ Slice 1 COMPLETE | -| Utils | change-utils | Change creation + name validation only | Slice 2 (new functionality only) | -| Core | InstructionLoader | Template resolution + enrichment | Slice 3 (all new) | -| Presentation | CLI | New artifact graph commands | Slice 4 (new commands only) | -| Integration | Claude Commands | AI assistant glue | Slice 4 | - -**What already exists (not in this proposal):** -- `getActiveChangeIds()` in `src/utils/item-discovery.ts` - list changes -- `ChangeCommand.list/show/validate()` in `src/commands/change.ts` -- `ListCommand.execute()` in `src/core/list.ts` -- `ViewCommand.execute()` in `src/core/view.ts` - dashboard -- `src/core/init.ts` - initialization -- `src/core/archive.ts` - archiving - -**Key Principles:** -- **Filesystem IS the database** - stateless, version-control friendly -- **Dependencies are enablers** - show what's possible, don't force order -- **Deterministic CLI, inferring agent** - CLI requires explicit `--change`, agent infers from context -- **XDG-compliant paths** - schemas and templates use standard user data directories -- **2-level inheritance** - user override → package built-in (no deeper) -- **Schemas are versioned** - support variations by philosophy, version, language diff --git a/docs/customization.md b/docs/customization.md index 3df392295..cd64bb7fb 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -1,2 +1,184 @@ # Customization +OpenSpec provides two levels of customization: + +1. **Project Config** (`openspec/config.yaml`) - Lightweight per-project customization for default schemas, shared context, and per-artifact rules +2. **Schema Overrides** - Full schema and template customization via XDG directories + +--- + +## Project Configuration + +The `openspec/config.yaml` file provides a lightweight customization layer that lets teams: + +- **Set a default schema** - New changes automatically use this schema instead of specifying `--schema` every time +- **Inject project context** - Shared context (tech stack, conventions) shown to AI when creating any artifact +- **Add per-artifact rules** - Custom rules that only apply to specific artifacts (e.g., proposal, specs) + +### Creating a Config + +You can create the config through the interactive setup: + +```bash +openspec init +``` + +Or create it manually: + +```yaml +# openspec/config.yaml +schema: spec-driven + +context: | + Tech stack: TypeScript, React, Node.js, PostgreSQL + API style: RESTful, documented in docs/api.md + Testing: Jest + React Testing Library + We value backwards compatibility for all public APIs + +rules: + proposal: + - Include rollback plan + - Identify affected teams + specs: + - Use Given/When/Then format + - Reference existing patterns before inventing new ones +``` + +### How Config Affects Workflows + +**Default schema selection:** + +```bash +# Without config: must specify schema +openspec new change my-feature --schema spec-driven + +# With config: schema is automatic +openspec new change my-feature +``` + +**Context and rules injection:** + +When generating instructions for an artifact, context and rules are injected: + +```xml + +Tech stack: TypeScript, React, Node.js, PostgreSQL +API style: RESTful, documented in docs/api.md +... + + + +- Include rollback plan +- Identify affected teams + + + +``` + +- **Context** appears in ALL artifacts +- **Rules** ONLY appear for the matching artifact + +### Schema Resolution Precedence + +1. CLI flag wins: `openspec new change feature --schema tdd` +2. Change metadata (if `.openspec.yaml` specifies schema) +3. Project config (`openspec/config.yaml`) +4. Default schema (`spec-driven`) + +### Error Handling + +The config provides graceful error handling: + +```bash +# Typo in schema name - shows suggestions +# Schema 'spec-drivne' not found +# Did you mean: spec-driven (built-in) + +# Unknown artifact ID in rules - warns but continues +# ⚠️ Unknown artifact ID in rules: "testplan". Valid IDs for schema "spec-driven": ... +``` + +--- + +## Schema Overrides + +For deeper customization, you can override entire schemas or templates. + +### How Schema Resolution Works + +OpenSpec uses a 2-level schema resolution system following the XDG Base Directory Specification: + +1. **User override**: `${XDG_DATA_HOME}/openspec/schemas//` +2. **Package built-in**: `/schemas//` + +When a schema is requested, the resolver checks the user directory first. If found, that entire schema directory is used. Otherwise, it falls back to the package's built-in schema. + +### Override Directories + +| Platform | Path | +|----------|------| +| macOS/Linux | `~/.local/share/openspec/schemas/` | +| Windows | `%LOCALAPPDATA%\openspec\schemas\` | +| All (if set) | `$XDG_DATA_HOME/openspec/schemas/` | + +### Manual Schema Override + +To override the default `spec-driven` schema: + +**1. Create the directory structure:** + +```bash +# macOS/Linux +mkdir -p ~/.local/share/openspec/schemas/spec-driven/templates +``` + +**2. Find and copy the default schema files:** + +```bash +# Find the package location +npm list -g openspec --parseable + +# Copy files from the package's schemas/ directory +cp /schemas/spec-driven/schema.yaml ~/.local/share/openspec/schemas/spec-driven/ +cp /schemas/spec-driven/templates/*.md ~/.local/share/openspec/schemas/spec-driven/templates/ +``` + +**3. Modify the copied files:** + +Edit `schema.yaml` to change the workflow structure: + +```yaml +name: spec-driven +version: 1 +description: My custom workflow +artifacts: + - id: proposal + generates: proposal.md + description: Initial proposal + template: proposal.md + requires: [] + # Add, remove, or modify artifacts... +``` + +Edit templates in `templates/` to customize the content guidance. + +### Current Limitations + +| Issue | Impact | +|-------|--------| +| **Path discovery** | Users must know XDG conventions and platform-specific paths | +| **Package location** | Finding the npm package path varies by install method | +| **No scaffolding** | Users must manually create directories and copy files | +| **No verification** | No way to confirm which schema is actually being resolved | +| **Full copy required** | Must copy entire schema even to change one template | + +### Related Files + +| File | Purpose | +|------|---------| +| `src/core/artifact-graph/resolver.ts` | Schema resolution logic | +| `src/core/artifact-graph/instruction-loader.ts` | Template loading | +| `src/core/global-config.ts` | XDG path helpers | +| `schemas/spec-driven/` | Default schema and templates | diff --git a/docs/experimental-release-plan.md b/docs/experimental-release-plan.md deleted file mode 100644 index 387b48cff..000000000 --- a/docs/experimental-release-plan.md +++ /dev/null @@ -1,926 +0,0 @@ -# OpenSpec Experimental Release Plan - -This document outlines the plan to release the experimental artifact workflow system for user testing. - -## Overview - -The goal is to allow users to test the new artifact-driven workflow system alongside the existing OpenSpec commands. This experimental system (`opsx`) provides a more granular, step-by-step approach to creating change artifacts. - -## Three Workflow Modes - -### 1. Old Workflow (Current Production) -- **Commands**: `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` -- **Behavior**: Hardcoded slash commands that generate all artifacts in one command -- **Status**: Production, unchanged - -### 2. New Artifact System - Batch Mode (Future) -- **Commands**: Refactored `/openspec:proposal` using schemas -- **Behavior**: Schema-driven but generates all artifacts at once (like legacy) -- **Status**: Not in scope for this experimental release -- **Note**: This is a future refactor to unify the old system with schemas - -### 3. New Artifact System - Granular Mode (Experimental) -- **Commands**: `/opsx:new`, `/opsx:continue` -- **Behavior**: One artifact at a time, dependency-driven, iterative -- **Status**: Target for this experimental release - ---- - -## Work Items - -### 1. Rename AWF to OPSX - -**Current State:** -- Commands: `/awf:start`, `/awf:continue` -- Files: `.claude/commands/awf/start.md`, `.claude/commands/awf/continue.md` - -**Target State:** -- Commands: `/opsx:new`, `/opsx:continue` -- Files: `.claude/commands/opsx/new.md`, `.claude/commands/opsx/continue.md` - -**Tasks:** -- [x] Create `.claude/commands/opsx/` directory -- [x] Rename `start.md` → `new.md` and update content -- [x] Copy `continue.md` with updated references -- [x] Update all references from "awf" to "opsx" in command content -- [x] Update frontmatter (name, description) to use "opsx" naming -- [x] Remove `.claude/commands/awf/` directory - -**CLI Commands:** -The underlying CLI commands (`openspec status`, `openspec instructions`, etc.) remain unchanged. Only the slash command names change. - ---- - -### 2. Remove WF Skill Files - -**Current State:** -- `.claude/commands/wf/start.md` - References non-existent `openspec wf` commands -- `.claude/commands/wf/continue.md` - References non-existent `openspec wf` commands - -**Target State:** -- Directory and files removed - -**Tasks:** -- [x] Delete `.claude/commands/wf/start.md` -- [x] Delete `.claude/commands/wf/continue.md` -- [x] Delete `.claude/commands/wf/` directory - ---- - -### 3. Add Agent Skills for Experimental Workflow - -**Purpose:** -Generate experimental workflow skills using the [Agent Skills](https://agentskills.io/specification) open standard. - -**Why Skills Instead of Slash Commands:** -- **Cross-editor compatibility**: Skills work in Claude Code, Cursor, Windsurf, and other compatible editors automatically -- **Simpler implementation**: Single directory (`.claude/skills/`) instead of 18+ editor-specific configurators -- **Standard format**: Open standard with simple YAML frontmatter + markdown -- **User invocation**: Users explicitly invoke skills when they want to use them - -**Behavior:** -1. Create `.claude/skills/` directory if it doesn't exist -2. Generate two skills using the Agent Skills specification: - - `openspec-new-change/SKILL.md` - Start a new change with artifact workflow - - `openspec-continue-change/SKILL.md` - Continue working on a change (create next artifact) -3. Skills are added **alongside** existing `/openspec:*` commands (not replacing) - -**Supported Editors:** -- Claude Code (native support) -- Cursor (native support via Settings → Rules → Import Settings) -- Windsurf (imports `.claude` configs) -- Cline, Codex, and other Agent Skills-compatible editors - -**Tasks:** -- [x] Create skill template content for `openspec-new-change` (based on current opsx:new) -- [x] Create skill template content for `openspec-continue-change` (based on current opsx:continue) -- [x] Add temporary `artifact-experimental-setup` command to CLI -- [x] Implement skill file generation (YAML frontmatter + markdown body) -- [x] Add success message with usage instructions - -**Note:** The `artifact-experimental-setup` command is temporary and will be merged into `openspec init` once the experimental workflow is promoted to stable. - -**Skill Format:** -Each skill is a directory with a `SKILL.md` file: -``` -.claude/skills/ -├── openspec-new-change/ -│ └── SKILL.md # name, description, instructions -├── openspec-continue-change/ -│ └── SKILL.md # name, description, instructions -└── openspec-apply-change/ - └── SKILL.md # name, description, instructions -``` - -**CLI Interface:** -```bash -openspec artifact-experimental-setup - -# Output: -# 🧪 Experimental Artifact Workflow Skills Created -# -# ✓ .claude/skills/openspec-new-change/SKILL.md -# ✓ .claude/skills/openspec-continue-change/SKILL.md -# ✓ .claude/skills/openspec-apply-change/SKILL.md -# -# 📖 Usage: -# -# Skills work automatically in compatible editors: -# • Claude Code - Auto-detected, ready to use -# • Cursor - Enable in Settings → Rules → Import Settings -# • Windsurf - Auto-imports from .claude directory -# -# Ask Claude naturally: -# • "I want to start a new OpenSpec change to add " -# • "Continue working on this change" -# -# Claude will automatically use the appropriate skill. -# -# 💡 This is an experimental feature. -# Feedback welcome at: https://github.com/Fission-AI/OpenSpec/issues -``` - -**Implementation Notes:** -- Simple file writing: Create directories and write templated `SKILL.md` files (no complex logic) -- Use existing `FileSystemUtils.writeFile()` pattern like slash command configurators -- Template structure: YAML frontmatter + markdown body -- Keep existing `/opsx:*` slash commands for now (manual cleanup later) -- Skills use invocation model (user explicitly asks Claude to use them) -- Skill `description` field guides when Claude suggests using the skill -- Each `SKILL.md` has required fields: `name` (matches directory) and `description` - ---- - -### 4. Update `/opsx:new` Command Content - -**Current Behavior (awf:start):** -1. Ask user what they want to build (if no input) -2. Create change directory -3. Show artifact status -4. Show what's ready -5. Get instructions for proposal -6. STOP and wait - -**New Behavior (opsx:new):** -Same flow but with updated naming: -- References to "awf" → "opsx" -- References to `/awf:continue` → `/opsx:continue` -- Update frontmatter name/description - -**Tasks:** -- [x] Update all "awf" references to "opsx" -- [x] Update command references in prompt text -- [x] Verify CLI commands still work (they use `openspec`, not `awf`) - ---- - -### 5. Update `/opsx:continue` Command Content - -**Current Behavior (awf:continue):** -1. Prompt for change selection (if not provided) -2. Check current status -3. Create ONE artifact based on what's ready -4. Show progress and what's unlocked -5. STOP - -**New Behavior (opsx:continue):** -Same flow with updated naming. - -**Tasks:** -- [x] Update all "awf" references to "opsx" -- [x] Update command references in prompt text - ---- - -### 6. End-to-End Testing - -**Objective:** -Run through a complete workflow with Claude using the new skills to create a real feature, validating the entire flow works. - -**Test Scenario:** -Use a real OpenSpec feature as the test case (dog-fooding). - -**Test Flow:** -1. Run `openspec artifact-experimental-setup` to create skills -2. Verify `.claude/skills/openspec-new-change/SKILL.md` created -3. Verify `.claude/skills/openspec-continue-change/SKILL.md` created -4. Verify `.claude/skills/openspec-apply-change/SKILL.md` created -5. Ask Claude: "I want to start a new OpenSpec change to add feature X" -6. Verify Claude invokes the `openspec-new-change` skill -7. Verify change directory created at `openspec/changes/add-feature-x/` -8. Verify proposal template shown -9. Ask Claude: "Continue working on this change" -10. Verify Claude invokes the `openspec-continue-change` skill -11. Verify `proposal.md` created with content -12. Ask Claude: "Continue" (create specs) -13. Verify `specs/*.md` created -14. Ask Claude: "Continue" (create design) -15. Verify `design.md` created -16. Ask Claude: "Continue" (create tasks) -17. Verify `tasks.md` created -18. Verify status shows 4/4 complete -19. Implement the feature based on tasks -20. Run `/openspec:archive` to archive the change - -**Validation Checklist:** -- [ ] `openspec artifact-experimental-setup` creates correct directory structure -- [ ] Skills are auto-detected in Claude Code -- [ ] Skill descriptions trigger appropriate invocations -- [ ] Skills create change directory and show proposal template -- [ ] Skills correctly identify ready artifacts -- [ ] Skills create artifacts with meaningful content -- [ ] Dependency detection works (specs requires proposal, etc.) -- [ ] Progress tracking is accurate -- [ ] Template content is useful and well-structured -- [ ] Error handling works (invalid names, missing changes, etc.) -- [ ] Works with different schemas (spec-driven, tdd) -- [ ] Test in Cursor (Settings → Rules → Import Settings) - -**Document Results:** -- Create test log documenting what worked and what didn't -- Note any friction points or confusing UX -- Identify bugs or improvements needed before user release - ---- - -### 7. Documentation for Users - -**Create user-facing documentation explaining:** - -1. **What is the experimental workflow?** - - A new way to create OpenSpec changes step-by-step using Agent Skills - - One artifact at a time with dependency tracking - - More interactive and iterative than the batch approach - - Works across Claude Code, Cursor, Windsurf, and other compatible editors - -2. **How to set up experimental workflow** - ```bash - openspec artifact-experimental-setup - ``` - - Note: This is a temporary command that will be integrated into `openspec init` once promoted to stable. - -3. **Available skills** - - `openspec-new-change` - Start a new change with artifact workflow - - `openspec-continue-change` - Continue working (create next artifact) - -4. **How to use** - - **Claude Code**: Skills are auto-detected, just ask Claude naturally - - "I want to start a new OpenSpec change to add X" - - "Continue working on this change" - - **Cursor**: Enable in Settings → Rules → Import Settings - - **Windsurf**: Auto-imports `.claude` directory - -5. **Example workflow** - - Step-by-step walkthrough with natural language interactions - - Show how Claude invokes skills based on user requests - -6. **Feedback mechanism** - - GitHub issue template for feedback - - What to report (bugs, UX issues, suggestions) - -**Tasks:** -- [ ] Create `docs/experimental-workflow.md` user guide -- [ ] Add GitHub issue template for experimental feedback -- [ ] Update README with mention of experimental features - ---- - -## Dependency Graph - -``` -1. Remove WF skill files - └── (no dependencies) - -2. Rename AWF to OPSX - └── (no dependencies) - -3. Add Agent Skills - └── Depends on: Rename AWF to OPSX (uses opsx content as templates) - -4. Update opsx:new content - └── Depends on: Rename AWF to OPSX - -5. Update opsx:continue content - └── Depends on: Rename AWF to OPSX - -6. E2E Testing - └── Depends on: Add Agent Skills (tests the skills workflow) - -7. User Documentation - └── Depends on: E2E Testing (need to know final behavior) -``` - ---- - -## Out of Scope - -The following are explicitly NOT part of this experimental release: - -1. **Batch mode refactor** - Making legacy `/openspec:proposal` use schemas -2. **New schemas** - Only shipping with existing `spec-driven` and `tdd` -3. **Schema customization UI** - No `openspec schema list` or similar -4. **Multiple editor support in CLI** - Skills work cross-editor automatically via `.claude/skills/` -5. **Replacing existing commands** - Skills are additive, not replacing `/openspec:*` or `/opsx:*` - ---- - -## Success Criteria - -The experimental release is ready when: - -1. `openspec-new-change`, `openspec-continue-change`, and `openspec-apply-change` skills work end-to-end -2. `openspec artifact-experimental-setup` creates skills in `.claude/skills/` -3. Skills work in Claude Code and are compatible with Cursor/Windsurf -4. At least one complete workflow has been tested manually -5. User documentation exists explaining how to generate and use skills -6. Feedback mechanism is in place -7. WF skill files are removed -8. No references to "awf" remain in user-facing content - ---- - -## Open Questions - -1. **Schema selection** - Should `opsx:new` allow selecting a schema, or always use `spec-driven`? - - Current: Always uses `spec-driven` as default - - Consider: Add `--schema tdd` option or prompt - -2. **Namespace in CLI** - Should experimental CLI commands be namespaced? - - Current: `openspec status`, `openspec instructions` (no namespace) - - Alternative: `openspec opsx status` (explicit experimental namespace) - - Recommendation: Keep current, less typing for users - -3. **Deprecation path** - If opsx becomes the default, how do we migrate? - - Not needed for experimental release - - Document that command names may change - ---- - -## Estimated Work Breakdown - -| Item | Complexity | Notes | -|------|------------|-------| -| Remove WF files | Trivial | Just delete 2 files + directory | -| Rename AWF → OPSX | Low | File renames + content updates | -| Add Agent Skills | **Low** | **Simple: 3-4 files, single output directory, standard format** | -| Update opsx:new content | Low | Text replacements | -| Update opsx:continue content | Low | Text replacements | -| E2E Testing | Medium | Manual testing, documenting results | -| User Documentation | Medium | New docs, issue template | - -**Key Improvement:** Switching to Agent Skills reduces complexity significantly: -- **Before:** 20+ files (type definitions, 18+ editor configurators, editor selection UI) -- **After:** 3-4 files (skill templates, simple CLI command) -- **Cross-editor:** Works automatically in Claude Code, Cursor, Windsurf without extra code - ---- - -## User Feedback from E2E Testing - -### What Worked Well - -1. **Clear dependency graph** ⭐ HIGH PRIORITY - KEEP - - The status command showing blocked/unblocked artifacts was intuitive: - ``` - [x] proposal - [ ] design - [-] tasks (blocked by: design, specs) - ``` - - Users always knew what they could work on next - - **Relevance**: Core UX strength to preserve - -2. **Structured instructions output** ⭐ HIGH PRIORITY - KEEP - - `openspec instructions ` gave templates, output paths, and context in one call - - Very helpful for understanding what to create - - **Relevance**: Essential for agent-driven workflow - -3. **Simple scaffolding** ✅ WORKS WELL - - `openspec new change "name"` just worked - created directory structure without fuss - - **Relevance**: Good baseline, room for improvement (see pain points) - ---- - -### Pain Points & Confusion - -1. **Redundant CLI calls** ⚠️ MEDIUM PRIORITY - - Users called both `status` AND `next` every time, but they overlap significantly - - `status` already shows what's blocked - - **Recommendation**: Consider merging or making `next` give actionable guidance beyond just listing names - - **Relevance**: Reduces friction in iterative workflow - -2. **Specs directory structure was ambiguous** 🔥 HIGH PRIORITY - FIX - - Instructions said: `Write to: .../specs/**/*.md` - - Users had to guess: `specs/spec.md`? `specs/game/spec.md`? `specs/tic-tac-toe/spec.md`? - - Users ended up doing manual `mkdir -p .../specs/tic-tac-toe` then writing `spec.md` inside - - **Recommendation**: CLI should scaffold this directory structure automatically - - **Relevance**: Critical agent UX - ambiguous paths cause workflow friction - -3. **Repetitive --change flag** ⚠️ MEDIUM PRIORITY - - Every command needed `--change "tic-tac-toe-game"` - - After 10+ calls, this felt verbose - - **Recommendation**: `openspec use "tic-tac-toe-game"` to set context, then subsequent commands assume that change - - **Relevance**: Quality of life improvement for iterative sessions - -4. **No validation feedback** 🔥 HIGH PRIORITY - ADD - - After writing each artifact, users just ran `status` hoping it would show `[x]` - - Questions raised: - - How did it know the artifact was "done"? File existence? - - What if spec format was wrong (e.g., wrong heading levels)? - - **Recommendation**: Add `openspec validate --change "name"` to check content quality - - **Relevance**: Critical for user confidence and catching errors early - -5. **Query-heavy, action-light CLI** 🔥 HIGH PRIORITY - ENHANCE - - Most commands retrieve info. The only "action" is `new change` - - Artifact creation is manual Write to guessed paths - - **Recommendation**: `openspec create proposal --change "name"` could scaffold the file with template pre-filled, then user just edits - - **Relevance**: Directly impacts agent productivity - reduce manual file writing - -6. **Instructions output was verbose** ⚠️ LOW PRIORITY - - XML-style output (``, `