-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat(cli): add multi-provider skill generation support #556
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8e332c8
6ec1234
1abda50
0ac4bb3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| schema: spec-driven | ||
| created: 2026-01-22 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| ## Context | ||
|
|
||
| The `artifact-experimental-setup` command generates skill files and opsx slash commands for AI coding assistants. Currently it hardcodes paths to `.claude/skills` and `.claude/commands/opsx`. | ||
|
|
||
| The existing `AI_TOOLS` array in `config.ts` lists 22 AI tools but lacks path information. There's also an existing `SlashCommandConfigurator` system for the old workflow commands, but it's tightly coupled to the old 3 commands (proposal, apply, archive) and can't be easily extended for the 9 opsx commands. | ||
|
|
||
| Each AI tool has: | ||
| - Different skill directory conventions (`.claude/skills/`, `.cursor/skills/`, etc.) | ||
| - Different command file paths (`.claude/commands/opsx/`, `.cursor/commands/`, etc.) | ||
| - Different frontmatter formats (YAML keys, structure varies by tool) | ||
|
|
||
| ## Goals / Non-Goals | ||
|
|
||
| **Goals:** | ||
| - Support skill generation for any AI tool following the Agent Skills spec | ||
| - Support command generation with tool-specific formatting via adapters | ||
| - Require explicit tool selection (no defaults) | ||
| - Create a generic, extensible command generation system | ||
|
|
||
| **Non-Goals:** | ||
| - Global path installation (deferred to future work) | ||
| - Multi-tool generation in single command (future enhancement) | ||
| - Unifying with existing SlashCommandConfigurator (separate systems for now) | ||
|
|
||
| ## Decisions | ||
|
|
||
| ### 1. Add `skillsDir` to `AIToolOption` interface | ||
|
|
||
| **Decision**: Add single `skillsDir` field to existing interface. No `commandsDir` or `globalSkillsDir`. | ||
|
|
||
| ```typescript | ||
| interface AIToolOption { | ||
| name: string; | ||
| value: string; | ||
| available: boolean; | ||
| successLabel?: string; | ||
| skillsDir?: string; // e.g., '.claude' - /skills suffix per Agent Skills spec | ||
| } | ||
| ``` | ||
|
|
||
| **Rationale**: | ||
| - Skills follow Agent Skills spec: `<toolDir>/skills/` - suffix is standard | ||
| - Commands need per-tool formatting, handled by adapters (not a simple path) | ||
| - Global paths deferred - can extend interface later | ||
|
|
||
| ### 2. Strategy/Adapter pattern for command generation | ||
|
|
||
| **Decision**: Create generic command generation with tool-specific adapters. | ||
|
|
||
| ```text | ||
| ┌─────────────────────────────────────────────────────────────────┐ | ||
| │ CommandContent │ | ||
| │ (tool-agnostic: id, name, description, category, tags, body) │ | ||
| └─────────────────────────────────────────────────────────────────┘ | ||
| │ | ||
| ▼ | ||
| ┌─────────────────────────────────────────────────────────────────┐ | ||
| │ generateCommand(content, adapter) │ | ||
| └─────────────────────────────────────────────────────────────────┘ | ||
| │ | ||
| ┌───────────────┼───────────────┐ | ||
| ▼ ▼ ▼ | ||
| ┌──────────┐ ┌──────────┐ ┌──────────┐ | ||
| │ Claude │ │ Cursor │ │ Windsurf │ | ||
| │ Adapter │ │ Adapter │ │ Adapter │ | ||
| └──────────┘ └──────────┘ └──────────┘ | ||
| ``` | ||
|
|
||
| **Interfaces:** | ||
|
|
||
| ```typescript | ||
| // Tool-agnostic command data | ||
| interface CommandContent { | ||
| id: string; // e.g., 'explore', 'new', 'apply' | ||
| name: string; // e.g., 'OpenSpec Explore' | ||
| description: string; // e.g., 'Enter explore mode...' | ||
| category: string; // e.g., 'OpenSpec' | ||
| tags: string[]; // e.g., ['openspec', 'explore'] | ||
| body: string; // The command instructions | ||
| } | ||
|
|
||
| // Per-tool formatting strategy | ||
| interface ToolCommandAdapter { | ||
| toolId: string; | ||
| getFilePath(commandId: string): string; | ||
| formatFile(content: CommandContent): string; | ||
| } | ||
| ``` | ||
|
|
||
| **Rationale**: | ||
| - Separates "what to generate" from "how to format it" | ||
| - Each tool's frontmatter quirks encapsulated in its adapter | ||
| - Easy to add new tools by implementing adapter interface | ||
| - Body content shared across all tools | ||
|
|
||
| **Alternative considered**: Extend existing SlashCommandConfigurator | ||
| - Rejected: Tightly coupled to old 3 commands, significant refactor needed | ||
|
|
||
| ### 3. Adapter registry pattern | ||
|
|
||
| **Decision**: Create `CommandAdapterRegistry` similar to existing `SlashCommandRegistry`. | ||
|
|
||
| ```typescript | ||
| class CommandAdapterRegistry { | ||
| private static adapters: Map<string, ToolCommandAdapter> = new Map(); | ||
|
|
||
| static get(toolId: string): ToolCommandAdapter | undefined; | ||
| static getAll(): ToolCommandAdapter[]; | ||
| } | ||
| ``` | ||
|
|
||
| **Rationale**: | ||
| - Consistent with existing codebase patterns | ||
| - Easy lookup by tool ID | ||
| - Centralized registration | ||
|
|
||
| ### 4. Required tool flag | ||
|
|
||
| **Decision**: Require `--tool` flag - error if omitted. | ||
|
|
||
| **Rationale**: | ||
| - Explicit tool selection avoids assumptions | ||
| - Consistent with project convention of not providing defaults | ||
| - Users must consciously choose their target tool | ||
|
|
||
| ## Risks / Trade-offs | ||
|
|
||
| **[Risk] Adapter maintenance burden** → Each new tool needs an adapter. Mitigated by simple interface - most adapters are ~20 lines. | ||
|
|
||
| **[Risk] Frontmatter format drift** → Tools may change their formats. Mitigated by encapsulating format in adapter - single place to update. | ||
|
|
||
| **[Trade-off] Two command systems** → Old SlashCommandConfigurator and new CommandAdapterRegistry coexist. Acceptable for now - can unify later if needed. | ||
|
|
||
| **[Trade-off] skillsDir optional** → Tools without skillsDir configured will error. Acceptable - we add paths as tools are tested. | ||
|
|
||
| ## Implementation Approach | ||
|
|
||
| 1. Add `skillsDir` to `AIToolOption` and populate for known tools | ||
| 2. Create `CommandContent` and `ToolCommandAdapter` interfaces | ||
| 3. Implement adapters for Claude, Cursor, Windsurf (start with 3) | ||
| 4. Create `CommandAdapterRegistry` | ||
| 5. Create `generateCommand()` function | ||
| 6. Update `artifact-experimental-setup` to use new system | ||
| 7. Add `--tool` flag with validation | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| ## Why | ||
|
|
||
| The `artifact-experimental-setup` command currently hardcodes skill output paths to `.claude/skills` and `.claude/commands/opsx`. This prevents users of other AI coding tools (Cursor, Windsurf, Codex, etc.) from using OpenSpec's skill generation. We need to support the diverse ecosystem of AI coding assistants, each with their own conventions for skill/instruction file locations and command frontmatter formats. | ||
|
|
||
| ## What Changes | ||
|
|
||
| - Add `skillsDir` path configuration to the existing `AIToolOption` interface in `config.ts` | ||
| - Add required `--tool <tool-id>` flag to the `artifact-experimental-setup` command | ||
| - Create a generic command generation system using Strategy/Adapter pattern: | ||
| - `CommandContent`: tool-agnostic command data (id, name, description, body) | ||
| - `ToolCommandAdapter`: per-tool formatting (file paths, frontmatter format) | ||
| - `CommandGenerator`: orchestrates generation using content + adapter | ||
| - Require explicit tool selection (no default) for clarity | ||
|
|
||
| ## Capabilities | ||
|
|
||
| ### New Capabilities | ||
|
|
||
| - `ai-tool-paths`: Configuration mapping AI tool IDs to their project-local skill directory paths | ||
| - `command-generation`: Generic command generation system with tool adapters for formatting differences | ||
|
|
||
| ### Modified Capabilities | ||
|
|
||
| - `cli-artifact-workflow`: Adding `--tool` flag to setup command for provider selection | ||
|
|
||
| ## Impact | ||
|
|
||
| - **Files Modified**: | ||
| - `src/core/config.ts` - Extend `AIToolOption` interface with `skillsDir` field | ||
| - `src/commands/artifact-workflow.ts` - Add `--tool` flag, use provider paths and adapters | ||
| - **New Files**: | ||
| - `src/core/command-generation/types.ts` - CommandContent, ToolCommandAdapter interfaces | ||
| - `src/core/command-generation/generator.ts` - Generic command generator | ||
| - `src/core/command-generation/adapters/*.ts` - Per-tool adapters | ||
|
Comment on lines
+28
to
+34
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add line-numbered file references. The proposal references files without line numbers; please use direct references like As per coding guidelines, use 🤖 Prompt for AI Agents |
||
| - **Backward Compatibility**: Existing workflows unaffected - this is a new command setup feature | ||
| - **User-Facing**: Required `--tool` flag on `artifact-experimental-setup` command for explicit tool selection | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| # ai-tool-paths Specification | ||
|
|
||
| ## Purpose | ||
|
|
||
| Define the path configuration for AI coding tool skill directories, enabling skill generation to target different tools following the Agent Skills spec. | ||
|
|
||
| ## Requirements | ||
|
|
||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: AIToolOption skillsDir field | ||
|
|
||
| The `AIToolOption` interface SHALL include an optional `skillsDir` field for skill generation path configuration. | ||
|
|
||
| #### Scenario: Interface includes skillsDir field | ||
|
|
||
| - **WHEN** a tool entry is defined in `AI_TOOLS` that supports skill generation | ||
| - **THEN** it SHALL include a `skillsDir` field specifying the project-local base directory (e.g., `.claude`) | ||
|
|
||
| #### Scenario: Skills path follows Agent Skills spec | ||
|
|
||
| - **WHEN** generating skills for a tool with `skillsDir: '.claude'` | ||
| - **THEN** skills SHALL be written to `<projectRoot>/<skillsDir>/skills/` | ||
| - **AND** the `/skills` suffix is appended per Agent Skills specification | ||
|
|
||
| ### Requirement: Path configuration for supported tools | ||
|
|
||
| The `AI_TOOLS` array SHALL include `skillsDir` for tools that support the Agent Skills specification. | ||
|
|
||
| #### Scenario: Claude Code paths defined | ||
|
|
||
| - **WHEN** looking up the `claude` tool | ||
| - **THEN** `skillsDir` SHALL be `.claude` | ||
|
|
||
| #### Scenario: Cursor paths defined | ||
|
|
||
| - **WHEN** looking up the `cursor` tool | ||
| - **THEN** `skillsDir` SHALL be `.cursor` | ||
|
|
||
| #### Scenario: Windsurf paths defined | ||
|
|
||
| - **WHEN** looking up the `windsurf` tool | ||
| - **THEN** `skillsDir` SHALL be `.windsurf` | ||
|
|
||
| #### Scenario: Tools without skillsDir | ||
|
|
||
| - **WHEN** a tool has no `skillsDir` defined | ||
| - **THEN** skill generation SHALL error with message indicating the tool is not supported | ||
|
|
||
| ### Requirement: Cross-platform path handling | ||
|
|
||
| The system SHALL handle paths correctly across operating systems. | ||
|
|
||
| #### Scenario: Path construction on Windows | ||
|
|
||
| - **WHEN** constructing skill paths on Windows | ||
| - **THEN** the system SHALL use `path.join()` for all path construction | ||
| - **AND** SHALL NOT hardcode forward slashes | ||
|
|
||
| #### Scenario: Path construction on Unix | ||
|
|
||
| - **WHEN** constructing skill paths on macOS or Linux | ||
| - **THEN** the system SHALL use `path.join()` for consistency |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # cli-artifact-workflow Delta Specification | ||
|
|
||
| ## Purpose | ||
|
|
||
| Add `--tool` flag to the `artifact-experimental-setup` command for multi-provider support. | ||
|
|
||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: Tool selection flag | ||
|
|
||
| The `artifact-experimental-setup` command SHALL accept a `--tool <tool-id>` flag to specify the target AI tool. | ||
|
|
||
| #### Scenario: Specify tool via flag | ||
|
|
||
| - **WHEN** user runs `openspec artifact-experimental-setup --tool cursor` | ||
| - **THEN** skill files are generated in `.cursor/skills/` | ||
| - **AND** command files are generated using Cursor's frontmatter format | ||
|
|
||
| #### Scenario: Missing tool flag | ||
|
|
||
| - **WHEN** user runs `openspec artifact-experimental-setup` without `--tool` | ||
| - **THEN** the system displays an error requiring the `--tool` flag | ||
| - **AND** lists valid tool IDs in the error message | ||
|
|
||
| #### Scenario: Unknown tool ID | ||
|
|
||
| - **WHEN** user runs `openspec artifact-experimental-setup --tool unknown-tool` | ||
| - **AND** the tool ID is not in `AI_TOOLS` | ||
| - **THEN** the system displays an error listing valid tool IDs | ||
|
|
||
| #### Scenario: Tool without skillsDir | ||
|
|
||
| - **WHEN** user specifies a tool that has no `skillsDir` configured | ||
| - **THEN** the system displays an error indicating skill generation is not supported for that tool | ||
|
|
||
| #### Scenario: Tool without command adapter | ||
|
|
||
| - **WHEN** user specifies a tool that has `skillsDir` but no command adapter registered | ||
| - **THEN** skill files are generated successfully | ||
| - **AND** command generation is skipped with informational message | ||
|
|
||
| ### Requirement: Output messaging | ||
|
|
||
| The setup command SHALL display clear output about what was generated. | ||
|
|
||
| #### Scenario: Show target tool in output | ||
|
|
||
| - **WHEN** setup command runs successfully | ||
| - **THEN** output includes the target tool name (e.g., "Setting up for Cursor...") | ||
|
|
||
| #### Scenario: Show generated paths | ||
|
|
||
| - **WHEN** setup command completes | ||
| - **THEN** output lists all generated skill file paths | ||
| - **AND** lists all generated command file paths (if applicable) | ||
|
|
||
| #### Scenario: Show skipped commands message | ||
|
|
||
| - **WHEN** command generation is skipped due to missing adapter | ||
| - **THEN** output includes message: "Command generation skipped - no adapter for <tool>" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use direct file references for mentioned code artifacts.
Please update references like
config.tsandSlashCommandConfiguratorto thefile.ts:lineformat (e.g.,src/core/config.ts:42) for clarity. As per coding guidelines, use direct file references in these design docs.🤖 Prompt for AI Agents