Two new OpenSpec skills for porting features to sandboxed codebases: - /opsx:extract-feature generates minimal, printable code recipes - /opsx:export-spec generates compact specs for AI-assisted reimplementation Both support cumulative dependency analysis across archived changes. Includes first export of migrate-to-semantic-kernel in all three formats: code recipe (~120 lines), portable spec (~40 lines), OpenSpec variant (~25 lines). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
218 lines
8.1 KiB
Markdown
218 lines
8.1 KiB
Markdown
---
|
|
name: openspec-export-spec
|
|
description: Export a feature as a compact, portable spec that an AI agent (Copilot, Claude) on a sandboxed machine can implement from. Optimized for minimal hand-typing.
|
|
license: MIT
|
|
compatibility: Requires openspec CLI.
|
|
metadata:
|
|
author: openspec
|
|
version: "1.0"
|
|
generatedBy: "1.2.0"
|
|
---
|
|
|
|
Export a feature as a portable spec for AI-assisted reimplementation on a sandboxed machine.
|
|
|
|
Instead of retyping code, you retype a compact spec. The AI on the sandbox (Copilot, Claude, OpenSpec) generates the code from the spec.
|
|
|
|
---
|
|
|
|
**Input**: A change name (active or archived), or a description of the feature. If omitted, prompt for selection.
|
|
|
|
**Steps**
|
|
|
|
1. **Identify the source feature**
|
|
|
|
Same as `openspec-extract-feature` step 1:
|
|
- Check active changes and archive for the change name
|
|
- If not found, prompt with **AskUserQuestion tool**
|
|
- Read all artifacts: `proposal.md`, `design.md`, `tasks.md`, specs
|
|
|
|
2. **Analyze dependency chain (cumulative mode)**
|
|
|
|
Features often build on each other. Before generating the spec, determine
|
|
what the target feature depends on.
|
|
|
|
a. **Read all archived change proposals** in `openspec/changes/archive/` (sorted by date).
|
|
For each, read `proposal.md` to understand what it adds and what it depends on.
|
|
|
|
b. **Build a dependency graph**:
|
|
- Which changes does the target feature require?
|
|
- Which earlier changes are superseded? (e.g., if Change 6 replaces Change 3's
|
|
implementation, include Change 6's version, not Change 3's)
|
|
- Which changes are unrelated and can be skipped?
|
|
|
|
c. **Ask the user** using **AskUserQuestion tool**:
|
|
> "This feature depends on earlier changes. How should I scope the spec?"
|
|
>
|
|
> Options:
|
|
> 1. **Cumulative** — include all foundation this feature needs (recommended if target is a fresh codebase)
|
|
> 2. **Delta only** — just what this specific change adds (use if target already has the foundation)
|
|
> 3. **Custom** — let me pick which dependencies to include
|
|
|
|
Show the dependency chain so the user can decide.
|
|
|
|
d. **In cumulative mode**: The spec covers the entire stack from foundation to feature.
|
|
- Merge packages, components, wiring from all included changes
|
|
- Skip superseded components (use the latest version)
|
|
- The spec should read as a single coherent feature, not a list of changes
|
|
|
|
e. **In delta mode**: The spec covers only the selected change.
|
|
- Add a "Assumes" section listing what must already exist in the target
|
|
|
|
3. **Read the actual implementation**
|
|
|
|
Read all source files that were created or modified by this feature
|
|
(and its dependencies if cumulative).
|
|
The spec must reflect what was actually built, not just what was planned.
|
|
|
|
4. **Determine the target context**
|
|
|
|
Use **AskUserQuestion tool** to ask:
|
|
> "Tell me about the target codebase:
|
|
> 1. Project name / root namespace
|
|
> 2. Existing stack (ASP.NET Core? Blazor? MudBlazor?)
|
|
> 3. Does it already have any of these? (controllers, DI setup, chat endpoint)
|
|
> 4. Does the target have OpenSpec? GitHub Copilot? Claude Code?"
|
|
|
|
This shapes what the spec assumes vs what it must specify.
|
|
|
|
5. **Generate the portable spec**
|
|
|
|
Create a single markdown document that is:
|
|
- **Compact**: Target ~30-50 lines for a medium feature
|
|
- **Precise**: Unambiguous enough for an AI to implement correctly
|
|
- **Self-contained**: No references to external files or repos
|
|
- **Stack-aware**: Uses the right terminology for the target stack
|
|
|
|
Structure:
|
|
|
|
```markdown
|
|
# Feature: <Name>
|
|
## Target: <project name> (<stack>)
|
|
|
|
## Packages
|
|
<list with versions>
|
|
|
|
## Architecture
|
|
<2-3 sentence overview of how the pieces fit together>
|
|
|
|
## Components
|
|
|
|
### <Component 1>: <path hint>
|
|
- <What it does — 1 line>
|
|
- <Key behavior — 1 line>
|
|
- <Interface/contract — 1 line>
|
|
|
|
### <Component 2>: <path hint>
|
|
...
|
|
|
|
## Contracts
|
|
<API shapes, model definitions, SSE formats — the things that MUST be exact>
|
|
|
|
## Wiring
|
|
<DI registration, middleware order, configuration keys — in dependency order>
|
|
|
|
## Behavior
|
|
<Key behavioral requirements that aren't obvious from the structure>
|
|
```
|
|
|
|
**Compression strategies:**
|
|
- Use bullet points, not prose
|
|
- Specify contracts precisely (field names, types, API shapes)
|
|
- Let the AI infer standard patterns (error handling, null checks, etc.)
|
|
- Only specify non-obvious behavior (the surprising parts)
|
|
- Omit anything the AI would do by default for the given stack
|
|
|
|
6. **Estimate typing effort**
|
|
|
|
Count characters in the spec. Compare to the code recipe equivalent.
|
|
Show the compression ratio:
|
|
```
|
|
Code recipe: ~120 lines to type
|
|
This spec: ~35 lines to type
|
|
Compression: 3.4x
|
|
```
|
|
|
|
7. **Optionally generate an OpenSpec-compatible version**
|
|
|
|
If the target has OpenSpec, also generate a version structured as:
|
|
- A `proposal.md` (minimal — 5-10 lines)
|
|
- A `tasks.md` (implementation steps the target AI follows)
|
|
|
|
These can be even more compact because OpenSpec provides the scaffolding.
|
|
|
|
Save this variant alongside the main spec.
|
|
|
|
8. **Write the output**
|
|
|
|
Save to: `openspec/exports/<change-name>-spec.md`
|
|
If OpenSpec variant: `openspec/exports/<change-name>-openspec.md`
|
|
|
|
Display the full content for review.
|
|
|
|
**Output Format**
|
|
|
|
```markdown
|
|
# Feature: Semantic Kernel Chat with Tool Calling
|
|
## Target: ApplicationX (ASP.NET Core + Blazor WASM + MudBlazor)
|
|
|
|
## Packages
|
|
- Microsoft.SemanticKernel 1.74.0
|
|
- Microsoft.SemanticKernel.Connectors.OpenAI 1.74.0
|
|
|
|
## Architecture
|
|
POST /api/chat endpoint accepts messages, runs them through SK's chat completion
|
|
with auto tool calling enabled, streams response as SSE. An ExtractionPlugin
|
|
validates structured data extracted by the LLM.
|
|
|
|
## Components
|
|
|
|
### ChatController: Controllers/ChatController.cs
|
|
- POST endpoint, injects Kernel via DI
|
|
- Converts ChatMessage[] to SK ChatHistory
|
|
- Streams via GetStreamingChatMessageContentsAsync
|
|
- Outputs SSE: `data: {"text":"..."}\n\n` then `data: [DONE]\n\n`
|
|
|
|
### ExtractionPlugin: Plugins/ExtractionPlugin.cs
|
|
- [KernelFunction("validate_extracted_fields")]
|
|
- Accepts JSON string, deserializes to ExtractedFields
|
|
- Returns {"isValid": bool, "errors": string[]}
|
|
|
|
### ExtractedFields: Models/ExtractedFields.cs
|
|
- Required: Client(string), Project(string), Hours(decimal), Rate(decimal), Currency(string), Date(string)
|
|
- Optional: Description(string), PoNumber(string)
|
|
|
|
### ValidationResult: Models/ValidationResult.cs
|
|
- IsValid(bool), Errors(List<string>)
|
|
|
|
### ChatRequest/ChatMessage: Shared/Models/
|
|
- ChatRequest: Messages(List<ChatMessage>)
|
|
- ChatMessage: Role(string), Content(string)
|
|
|
|
## Wiring (Program.cs, add after AddControllers)
|
|
- AddOpenAIChatCompletion(model, endpoint with /v1 suffix, apiKey)
|
|
- AddKernel()
|
|
- AddSingleton<ExtractionPlugin>()
|
|
- UseCors for Blazor client origin
|
|
|
|
## Behavior
|
|
- FunctionChoiceBehavior.Auto() enables autonomous tool calling
|
|
- SK's built-in limit prevents runaway tool call loops
|
|
- Plugin imported per-request via _kernel.ImportPluginFromObject
|
|
- Base URL must include /v1 — OpenAI SDK appends chat/completions directly
|
|
```
|
|
|
|
**Lines to type: ~35 | Code equivalent: ~150 lines | Compression: 4.3x**
|
|
|
|
**Guardrails**
|
|
- Prioritize precision over brevity — an ambiguous spec wastes more time than a slightly longer one
|
|
- Always include exact field names, types, and API shapes — these are the hardest to guess
|
|
- Include non-obvious gotchas (like the /v1 base URL requirement)
|
|
- Test the spec mentally: could an AI implement this correctly without seeing the original code?
|
|
- If the feature is too complex for a single spec page (~50+ lines), split into multiple specs by component
|
|
- Always show the compression ratio so the user can decide between spec and code recipe
|
|
- The spec must be readable when printed in monospace — no wide tables or long lines
|
|
- In cumulative mode, the spec must read as one coherent feature — not a list of sequential changes
|
|
- Skip superseded components — always describe the latest version of each piece
|
|
- In delta mode, add an "Assumes" section so the target AI knows what must already exist
|
|
- In the output header, note which changes were included and which were skipped
|