zhengyi Copilot commited on
Commit
ba681c7
·
0 Parent(s):

feat: 實現深色模式功能

Browse files

- 新增主題切換 UI 按鈕
- 實現主題持久化儲存 (localStorage)
- 支援亮色/深色主題樣式
- 適配 Plotly 圖表主題
- WCAG AA 無障礙標準

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .claude/skills/skill-creator/SKILL.md +97 -0
  2. .github/agents/azure_task_implementer.agent.md +1 -0
  3. .github/agents/azure_task_plan.agent.md +1 -0
  4. .github/agents/azure_task_specify.agent.md +5 -0
  5. .github/copilot-instructions.md +58 -0
  6. .github/prompts/azure_task_specify.prompt.md +13 -0
  7. .github/prompts/opsx-apply.prompt.md +149 -0
  8. .github/prompts/opsx-archive.prompt.md +154 -0
  9. .github/prompts/opsx-bulk-archive.prompt.md +239 -0
  10. .github/prompts/opsx-continue.prompt.md +111 -0
  11. .github/prompts/opsx-explore.prompt.md +170 -0
  12. .github/prompts/opsx-ff.prompt.md +94 -0
  13. .github/prompts/opsx-new.prompt.md +66 -0
  14. .github/prompts/opsx-onboard.prompt.md +547 -0
  15. .github/prompts/opsx-sync.prompt.md +131 -0
  16. .github/prompts/opsx-verify.prompt.md +161 -0
  17. .github/skills/openspec-apply-change/SKILL.md +156 -0
  18. .github/skills/openspec-archive-change/SKILL.md +114 -0
  19. .github/skills/openspec-bulk-archive-change/SKILL.md +246 -0
  20. .github/skills/openspec-continue-change/SKILL.md +118 -0
  21. .github/skills/openspec-explore/SKILL.md +288 -0
  22. .github/skills/openspec-ff-change/SKILL.md +101 -0
  23. .github/skills/openspec-new-change/SKILL.md +74 -0
  24. .github/skills/openspec-onboard/SKILL.md +554 -0
  25. .github/skills/openspec-sync-specs/SKILL.md +138 -0
  26. .github/skills/openspec-verify-change/SKILL.md +168 -0
  27. .vscode/mcp.json +3 -0
  28. .vscode/settings.json +7 -0
  29. ChatMemo.txt +103 -0
  30. DARK_MODE_GUIDE.md +90 -0
  31. StockList.xlsx +0 -0
  32. __pycache__/app.cpython-313.pyc +0 -0
  33. app.py +0 -0
  34. app_batch.py +1104 -0
  35. css/dark_mode.css +231 -0
  36. docs/specify/plan/專案名稱/SDS.md +0 -0
  37. docs/specify/plan/專案名稱/SRS.md +0 -0
  38. docs/specify/plan/專案名稱/spec.md +0 -0
  39. docs/specify/plan/專案名稱/tasks.md +1 -0
  40. docs/specify/plan/放AI產生的plan文件 +0 -0
  41. docs/specify/templates/放AI參考的文件格式 +0 -0
  42. openspec/changes/archive/2026-03-10-add-dark-mode/.openspec.yaml +2 -0
  43. openspec/changes/archive/2026-03-10-add-dark-mode/design.md +89 -0
  44. openspec/changes/archive/2026-03-10-add-dark-mode/proposal.md +34 -0
  45. openspec/changes/archive/2026-03-10-add-dark-mode/specs/chart-theme-support/spec.md +49 -0
  46. openspec/changes/archive/2026-03-10-add-dark-mode/specs/dark-mode-styling/spec.md +45 -0
  47. openspec/changes/archive/2026-03-10-add-dark-mode/specs/theme-persistence/spec.md +45 -0
  48. openspec/changes/archive/2026-03-10-add-dark-mode/specs/theme-toggle-ui/spec.md +45 -0
  49. openspec/changes/archive/2026-03-10-add-dark-mode/tasks.md +53 -0
  50. openspec/config.yaml +19 -0
.claude/skills/skill-creator/SKILL.md ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: skill-creator
3
+ description: Guide for creating effective skills. Use when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
4
+ source: anthropics/skills
5
+ license: Apache-2.0
6
+ ---
7
+
8
+ # Skill Creator
9
+
10
+ Skills are modular packages that extend Claude's capabilities by providing specialized knowledge, workflows, and tools.
11
+
12
+ ## Core Principles
13
+
14
+ ### Concise is Key
15
+ The context window is a shared resource. Only add context Claude doesn't already have. Challenge each piece: "Does Claude really need this?"
16
+
17
+ ### Anatomy of a Skill
18
+
19
+ ```
20
+ skill-name/
21
+ ├── SKILL.md (required)
22
+ │ ├── YAML frontmatter (name, description)
23
+ │ └── Markdown instructions
24
+ └── Bundled Resources (optional)
25
+ ├── scripts/ - Executable code
26
+ ├── references/ - Documentation
27
+ └── assets/ - Templates, images
28
+ ```
29
+
30
+ ### SKILL.md Format
31
+
32
+ ```markdown
33
+ ---
34
+ name: my-skill-name
35
+ description: A clear description of what this skill does and when to use it
36
+ ---
37
+
38
+ # My Skill Name
39
+
40
+ [Instructions for Claude when this skill is active]
41
+
42
+ ## Examples
43
+ - Example usage 1
44
+ - Example usage 2
45
+
46
+ ## Guidelines
47
+ - Guideline 1
48
+ - Guideline 2
49
+ ```
50
+
51
+ ## Skill Creation Process
52
+
53
+ ### Step 1: Understand with Examples
54
+ Gather concrete examples of how the skill will be used. Ask:
55
+ - "What functionality should this skill support?"
56
+ - "What would a user say that should trigger this skill?"
57
+
58
+ ### Step 2: Plan Reusable Contents
59
+ Analyze examples to identify:
60
+ - **Scripts**: Code that gets rewritten repeatedly
61
+ - **References**: Documentation Claude needs to reference
62
+ - **Assets**: Templates, images for output
63
+
64
+ ### Step 3: Initialize
65
+ Create the skill directory structure with SKILL.md and resource folders.
66
+
67
+ ### Step 4: Implement
68
+ - Start with reusable resources (scripts, references, assets)
69
+ - Write clear SKILL.md with proper frontmatter
70
+ - Test scripts by actually running them
71
+
72
+ ### Step 5: Iterate
73
+ Use the skill on real tasks, notice struggles, improve.
74
+
75
+ ## Progressive Disclosure
76
+
77
+ Keep SKILL.md under 500 lines. Split content:
78
+
79
+ ```markdown
80
+ # PDF Processing
81
+
82
+ ## Quick start
83
+ [code example]
84
+
85
+ ## Advanced features
86
+ - **Form filling**: See [FORMS.md](FORMS.md)
87
+ - **API reference**: See [REFERENCE.md](REFERENCE.md)
88
+ ```
89
+
90
+ ## What NOT to Include
91
+
92
+ - README.md
93
+ - INSTALLATION_GUIDE.md
94
+ - CHANGELOG.md
95
+ - User-facing documentation
96
+
97
+ Skills are for AI agents, not humans.
.github/agents/azure_task_implementer.agent.md ADDED
@@ -0,0 +1 @@
 
 
1
+ # StockRecommender - AI Coding Agent ���� specify
.github/agents/azure_task_plan.agent.md ADDED
@@ -0,0 +1 @@
 
 
1
+ # StockRecommender - AI Coding Agent ���� specify
.github/agents/azure_task_specify.agent.md ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # StockRecommender - AI Coding Agent ���� specify
2
+
3
+ ### ����ԲӸ��
4
+
5
+ 1.**���Task ���㤺�e**�G
.github/copilot-instructions.md ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # StockRecommender - AI Coding Agent Instructions
2
+
3
+ ## Language
4
+ **��ҡB�^�СB���ͤ��B���ѡA�Ф@�ߨϥ��c�餤��A�èϥΥx�W�`�ε��J�C
5
+
6
+ ## Project Overview
7
+ **StockRecommender** is a Python-based AI stock analysis tool designed to run on **Hugging Face Spaces** or locally. It uses **Gradio** for the web interface and leverages **yfinance** for market data and **Transformers** (FinBERT, BART) for sentiment analysis and summarization.
8
+
9
+ ## Architecture & Key Files
10
+ - **`app_batch.py`**: The main application file with advanced features.
11
+ - **Batch Analysis**: Supports analyzing multiple stocks via text input or file.
12
+ - **Visualization**: Uses Plotly for interactive charts (Bar, Scatter, Radar, Pie).
13
+ - **Tabs**: Separates "Single Stock Analysis" and "Batch Stock Analysis".
14
+ - **`app.py`**: A lighter/older version of the application, primarily for single stock analysis.
15
+ - **`requirements.txt`**: Lists all Python dependencies.
16
+ - **`StockList.xlsx`**: (Optional) Source for batch analysis if configured.
17
+
18
+ ## Environment & Setup
19
+ - **Hugging Face Spaces**: The app detects if it's running in HF Spaces via `IS_HUGGINGFACE_SPACE` (checks for `SPACE_ID` env var).
20
+ - **Runtime Package Installation**: The code includes a `install_package` function to auto-install missing dependencies at runtime. This is a specific pattern to ensure robustness in different environments.
21
+
22
+ ## Core Components
23
+ ### StockAnalyzer Class
24
+ - Handles data fetching via `yfinance`.
25
+ - Performs technical analysis (Moving Averages, RSI, MACD).
26
+ - Integrates AI models for sentiment analysis (if available).
27
+
28
+ ### AI Models
29
+ - **Sentiment**: `ProsusAI/finbert` (fallback: `nlptown/bert-base-multilingual-uncased-sentiment`).
30
+ - **Summarization**: `facebook/bart-large-cnn` (fallback: `sshleifer/distilbart-cnn-12-6`).
31
+ - **Fallback**: If models fail to load (e.g., memory constraints), the app falls back to lightweight internal analysis methods.
32
+
33
+ ## Developer Workflows
34
+ - **Running Locally**:
35
+ ```bash
36
+ python app_batch.py
37
+ ```
38
+ - **Dependencies**:
39
+ Always update `requirements.txt` when adding new packages, even though runtime installation exists.
40
+ ```bash
41
+ pip install -r requirements.txt
42
+ ```
43
+
44
+ ## Coding Conventions
45
+ - **Error Handling**: Wrap external API calls (yfinance, HF pipeline) in `try-except` blocks to prevent app crashes.
46
+ - **UI Updates**: When modifying the UI, ensure Gradio components are properly nested in `gr.Row()` and `gr.Column()` for layout control.
47
+ - **Data Visualization**: Use `plotly.graph_objects` and `plotly.express` for charts; return them as `gr.Plot` objects.
48
+
49
+ ## Common Patterns
50
+ - **Runtime Import Checks**:
51
+ ```python
52
+ try:
53
+ import some_package
54
+ except ImportError:
55
+ install_package("some_package")
56
+ ```
57
+ - **Gradio Event Listeners**:
58
+ Use `.click()` or `.change()` to bind functions to UI elements.
.github/prompts/azure_task_specify.prompt.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ agent: azure_task_specify
3
+ ---
4
+
5
+ # User Request
6
+ �Ш�U�ڶi��ݨD����P�W��w�q�C
7
+
8
+ Task ID / Context:
9
+ ```text
10
+ $ARGUMENTS
11
+ $SELECTION
12
+ ````
13
+
.github/prompts/opsx-apply.prompt.md ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ description: Implement tasks from an OpenSpec change (Experimental)
3
+ ---
4
+
5
+ Implement tasks from an OpenSpec change.
6
+
7
+ **Input**: Optionally specify a change name (e.g., `/opsx:apply add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
8
+
9
+ **Steps**
10
+
11
+ 1. **Select the change**
12
+
13
+ If a name is provided, use it. Otherwise:
14
+ - Infer from conversation context if the user mentioned a change
15
+ - Auto-select if only one active change exists
16
+ - If ambiguous, run `openspec list --json` to get available changes and use the **AskUserQuestion tool** to let the user select
17
+
18
+ Always announce: "Using change: <name>" and how to override (e.g., `/opsx:apply <other>`).
19
+
20
+ 2. **Check status to understand the schema**
21
+ ```bash
22
+ openspec status --change "<name>" --json
23
+ ```
24
+ Parse the JSON to understand:
25
+ - `schemaName`: The workflow being used (e.g., "spec-driven")
26
+ - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others)
27
+
28
+ 3. **Get apply instructions**
29
+
30
+ ```bash
31
+ openspec instructions apply --change "<name>" --json
32
+ ```
33
+
34
+ This returns:
35
+ - Context file paths (varies by schema)
36
+ - Progress (total, complete, remaining)
37
+ - Task list with status
38
+ - Dynamic instruction based on current state
39
+
40
+ **Handle states:**
41
+ - If `state: "blocked"` (missing artifacts): show message, suggest using `/opsx:continue`
42
+ - If `state: "all_done"`: congratulate, suggest archive
43
+ - Otherwise: proceed to implementation
44
+
45
+ 4. **Read context files**
46
+
47
+ Read the files listed in `contextFiles` from the apply instructions output.
48
+ The files depend on the schema being used:
49
+ - **spec-driven**: proposal, specs, design, tasks
50
+ - Other schemas: follow the contextFiles from CLI output
51
+
52
+ 5. **Show current progress**
53
+
54
+ Display:
55
+ - Schema being used
56
+ - Progress: "N/M tasks complete"
57
+ - Remaining tasks overview
58
+ - Dynamic instruction from CLI
59
+
60
+ 6. **Implement tasks (loop until done or blocked)**
61
+
62
+ For each pending task:
63
+ - Show which task is being worked on
64
+ - Make the code changes required
65
+ - Keep changes minimal and focused
66
+ - Mark task complete in the tasks file: `- [ ]` → `- [x]`
67
+ - Continue to next task
68
+
69
+ **Pause if:**
70
+ - Task is unclear → ask for clarification
71
+ - Implementation reveals a design issue → suggest updating artifacts
72
+ - Error or blocker encountered → report and wait for guidance
73
+ - User interrupts
74
+
75
+ 7. **On completion or pause, show status**
76
+
77
+ Display:
78
+ - Tasks completed this session
79
+ - Overall progress: "N/M tasks complete"
80
+ - If all done: suggest archive
81
+ - If paused: explain why and wait for guidance
82
+
83
+ **Output During Implementation**
84
+
85
+ ```
86
+ ## Implementing: <change-name> (schema: <schema-name>)
87
+
88
+ Working on task 3/7: <task description>
89
+ [...implementation happening...]
90
+ ✓ Task complete
91
+
92
+ Working on task 4/7: <task description>
93
+ [...implementation happening...]
94
+ ✓ Task complete
95
+ ```
96
+
97
+ **Output On Completion**
98
+
99
+ ```
100
+ ## Implementation Complete
101
+
102
+ **Change:** <change-name>
103
+ **Schema:** <schema-name>
104
+ **Progress:** 7/7 tasks complete ✓
105
+
106
+ ### Completed This Session
107
+ - [x] Task 1
108
+ - [x] Task 2
109
+ ...
110
+
111
+ All tasks complete! You can archive this change with `/opsx:archive`.
112
+ ```
113
+
114
+ **Output On Pause (Issue Encountered)**
115
+
116
+ ```
117
+ ## Implementation Paused
118
+
119
+ **Change:** <change-name>
120
+ **Schema:** <schema-name>
121
+ **Progress:** 4/7 tasks complete
122
+
123
+ ### Issue Encountered
124
+ <description of the issue>
125
+
126
+ **Options:**
127
+ 1. <option 1>
128
+ 2. <option 2>
129
+ 3. Other approach
130
+
131
+ What would you like to do?
132
+ ```
133
+
134
+ **Guardrails**
135
+ - Keep going through tasks until done or blocked
136
+ - Always read context files before starting (from the apply instructions output)
137
+ - If task is ambiguous, pause and ask before implementing
138
+ - If implementation reveals issues, pause and suggest artifact updates
139
+ - Keep code changes minimal and scoped to each task
140
+ - Update task checkbox immediately after completing each task
141
+ - Pause on errors, blockers, or unclear requirements - don't guess
142
+ - Use contextFiles from CLI output, don't assume specific file names
143
+
144
+ **Fluid Workflow Integration**
145
+
146
+ This skill supports the "actions on a change" model:
147
+
148
+ - **Can be invoked anytime**: Before all artifacts are done (if tasks exist), after partial implementation, interleaved with other actions
149
+ - **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly
.github/prompts/opsx-archive.prompt.md ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ description: Archive a completed change in the experimental workflow
3
+ ---
4
+
5
+ Archive a completed change in the experimental workflow.
6
+
7
+ **Input**: Optionally specify a change name after `/opsx:archive` (e.g., `/opsx:archive add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
8
+
9
+ **Steps**
10
+
11
+ 1. **If no change name provided, prompt for selection**
12
+
13
+ Run `openspec list --json` to get available changes. Use the **AskUserQuestion tool** to let the user select.
14
+
15
+ Show only active changes (not already archived).
16
+ Include the schema used for each change if available.
17
+
18
+ **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
19
+
20
+ 2. **Check artifact completion status**
21
+
22
+ Run `openspec status --change "<name>" --json` to check artifact completion.
23
+
24
+ Parse the JSON to understand:
25
+ - `schemaName`: The workflow being used
26
+ - `artifacts`: List of artifacts with their status (`done` or other)
27
+
28
+ **If any artifacts are not `done`:**
29
+ - Display warning listing incomplete artifacts
30
+ - Prompt user for confirmation to continue
31
+ - Proceed if user confirms
32
+
33
+ 3. **Check task completion status**
34
+
35
+ Read the tasks file (typically `tasks.md`) to check for incomplete tasks.
36
+
37
+ Count tasks marked with `- [ ]` (incomplete) vs `- [x]` (complete).
38
+
39
+ **If incomplete tasks found:**
40
+ - Display warning showing count of incomplete tasks
41
+ - Prompt user for confirmation to continue
42
+ - Proceed if user confirms
43
+
44
+ **If no tasks file exists:** Proceed without task-related warning.
45
+
46
+ 4. **Assess delta spec sync state**
47
+
48
+ Check for delta specs at `openspec/changes/<name>/specs/`. If none exist, proceed without sync prompt.
49
+
50
+ **If delta specs exist:**
51
+ - Compare each delta spec with its corresponding main spec at `openspec/specs/<capability>/spec.md`
52
+ - Determine what changes would be applied (adds, modifications, removals, renames)
53
+ - Show a combined summary before prompting
54
+
55
+ **Prompt options:**
56
+ - If changes needed: "Sync now (recommended)", "Archive without syncing"
57
+ - If already synced: "Archive now", "Sync anyway", "Cancel"
58
+
59
+ If user chooses sync, use Task tool (subagent_type: "general-purpose", prompt: "Use Skill tool to invoke openspec-sync-specs for change '<name>'. Delta spec analysis: <include the analyzed delta spec summary>"). Proceed to archive regardless of choice.
60
+
61
+ 5. **Perform the archive**
62
+
63
+ Create the archive directory if it doesn't exist:
64
+ ```bash
65
+ mkdir -p openspec/changes/archive
66
+ ```
67
+
68
+ Generate target name using current date: `YYYY-MM-DD-<change-name>`
69
+
70
+ **Check if target already exists:**
71
+ - If yes: Fail with error, suggest renaming existing archive or using different date
72
+ - If no: Move the change directory to archive
73
+
74
+ ```bash
75
+ mv openspec/changes/<name> openspec/changes/archive/YYYY-MM-DD-<name>
76
+ ```
77
+
78
+ 6. **Display summary**
79
+
80
+ Show archive completion summary including:
81
+ - Change name
82
+ - Schema that was used
83
+ - Archive location
84
+ - Spec sync status (synced / sync skipped / no delta specs)
85
+ - Note about any warnings (incomplete artifacts/tasks)
86
+
87
+ **Output On Success**
88
+
89
+ ```
90
+ ## Archive Complete
91
+
92
+ **Change:** <change-name>
93
+ **Schema:** <schema-name>
94
+ **Archived to:** openspec/changes/archive/YYYY-MM-DD-<name>/
95
+ **Specs:** ✓ Synced to main specs
96
+
97
+ All artifacts complete. All tasks complete.
98
+ ```
99
+
100
+ **Output On Success (No Delta Specs)**
101
+
102
+ ```
103
+ ## Archive Complete
104
+
105
+ **Change:** <change-name>
106
+ **Schema:** <schema-name>
107
+ **Archived to:** openspec/changes/archive/YYYY-MM-DD-<name>/
108
+ **Specs:** No delta specs
109
+
110
+ All artifacts complete. All tasks complete.
111
+ ```
112
+
113
+ **Output On Success With Warnings**
114
+
115
+ ```
116
+ ## Archive Complete (with warnings)
117
+
118
+ **Change:** <change-name>
119
+ **Schema:** <schema-name>
120
+ **Archived to:** openspec/changes/archive/YYYY-MM-DD-<name>/
121
+ **Specs:** Sync skipped (user chose to skip)
122
+
123
+ **Warnings:**
124
+ - Archived with 2 incomplete artifacts
125
+ - Archived with 3 incomplete tasks
126
+ - Delta spec sync was skipped (user chose to skip)
127
+
128
+ Review the archive if this was not intentional.
129
+ ```
130
+
131
+ **Output On Error (Archive Exists)**
132
+
133
+ ```
134
+ ## Archive Failed
135
+
136
+ **Change:** <change-name>
137
+ **Target:** openspec/changes/archive/YYYY-MM-DD-<name>/
138
+
139
+ Target archive directory already exists.
140
+
141
+ **Options:**
142
+ 1. Rename the existing archive
143
+ 2. Delete the existing archive if it's a duplicate
144
+ 3. Wait until a different date to archive
145
+ ```
146
+
147
+ **Guardrails**
148
+ - Always prompt for change selection if not provided
149
+ - Use artifact graph (openspec status --json) for completion checking
150
+ - Don't block archive on warnings - just inform and confirm
151
+ - Preserve .openspec.yaml when moving to archive (it moves with the directory)
152
+ - Show clear summary of what happened
153
+ - If sync is requested, use the Skill tool to invoke `openspec-sync-specs` (agent-driven)
154
+ - If delta specs exist, always run the sync assessment and show the combined summary before prompting
.github/prompts/opsx-bulk-archive.prompt.md ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ description: Archive multiple completed changes at once
3
+ ---
4
+
5
+ Archive multiple completed changes in a single operation.
6
+
7
+ This skill allows you to batch-archive changes, handling spec conflicts intelligently by checking the codebase to determine what's actually implemented.
8
+
9
+ **Input**: None required (prompts for selection)
10
+
11
+ **Steps**
12
+
13
+ 1. **Get active changes**
14
+
15
+ Run `openspec list --json` to get all active changes.
16
+
17
+ If no active changes exist, inform user and stop.
18
+
19
+ 2. **Prompt for change selection**
20
+
21
+ Use **AskUserQuestion tool** with multi-select to let user choose changes:
22
+ - Show each change with its schema
23
+ - Include an option for "All changes"
24
+ - Allow any number of selections (1+ works, 2+ is the typical use case)
25
+
26
+ **IMPORTANT**: Do NOT auto-select. Always let the user choose.
27
+
28
+ 3. **Batch validation - gather status for all selected changes**
29
+
30
+ For each selected change, collect:
31
+
32
+ a. **Artifact status** - Run `openspec status --change "<name>" --json`
33
+ - Parse `schemaName` and `artifacts` list
34
+ - Note which artifacts are `done` vs other states
35
+
36
+ b. **Task completion** - Read `openspec/changes/<name>/tasks.md`
37
+ - Count `- [ ]` (incomplete) vs `- [x]` (complete)
38
+ - If no tasks file exists, note as "No tasks"
39
+
40
+ c. **Delta specs** - Check `openspec/changes/<name>/specs/` directory
41
+ - List which capability specs exist
42
+ - For each, extract requirement names (lines matching `### Requirement: <name>`)
43
+
44
+ 4. **Detect spec conflicts**
45
+
46
+ Build a map of `capability -> [changes that touch it]`:
47
+
48
+ ```
49
+ auth -> [change-a, change-b] <- CONFLICT (2+ changes)
50
+ api -> [change-c] <- OK (only 1 change)
51
+ ```
52
+
53
+ A conflict exists when 2+ selected changes have delta specs for the same capability.
54
+
55
+ 5. **Resolve conflicts agentically**
56
+
57
+ **For each conflict**, investigate the codebase:
58
+
59
+ a. **Read the delta specs** from each conflicting change to understand what each claims to add/modify
60
+
61
+ b. **Search the codebase** for implementation evidence:
62
+ - Look for code implementing requirements from each delta spec
63
+ - Check for related files, functions, or tests
64
+
65
+ c. **Determine resolution**:
66
+ - If only one change is actually implemented -> sync that one's specs
67
+ - If both implemented -> apply in chronological order (older first, newer overwrites)
68
+ - If neither implemented -> skip spec sync, warn user
69
+
70
+ d. **Record resolution** for each conflict:
71
+ - Which change's specs to apply
72
+ - In what order (if both)
73
+ - Rationale (what was found in codebase)
74
+
75
+ 6. **Show consolidated status table**
76
+
77
+ Display a table summarizing all changes:
78
+
79
+ ```
80
+ | Change | Artifacts | Tasks | Specs | Conflicts | Status |
81
+ |---------------------|-----------|-------|---------|-----------|--------|
82
+ | schema-management | Done | 5/5 | 2 delta | None | Ready |
83
+ | project-config | Done | 3/3 | 1 delta | None | Ready |
84
+ | add-oauth | Done | 4/4 | 1 delta | auth (!) | Ready* |
85
+ | add-verify-skill | 1 left | 2/5 | None | None | Warn |
86
+ ```
87
+
88
+ For conflicts, show the resolution:
89
+ ```
90
+ * Conflict resolution:
91
+ - auth spec: Will apply add-oauth then add-jwt (both implemented, chronological order)
92
+ ```
93
+
94
+ For incomplete changes, show warnings:
95
+ ```
96
+ Warnings:
97
+ - add-verify-skill: 1 incomplete artifact, 3 incomplete tasks
98
+ ```
99
+
100
+ 7. **Confirm batch operation**
101
+
102
+ Use **AskUserQuestion tool** with a single confirmation:
103
+
104
+ - "Archive N changes?" with options based on status
105
+ - Options might include:
106
+ - "Archive all N changes"
107
+ - "Archive only N ready changes (skip incomplete)"
108
+ - "Cancel"
109
+
110
+ If there are incomplete changes, make clear they'll be archived with warnings.
111
+
112
+ 8. **Execute archive for each confirmed change**
113
+
114
+ Process changes in the determined order (respecting conflict resolution):
115
+
116
+ a. **Sync specs** if delta specs exist:
117
+ - Use the openspec-sync-specs approach (agent-driven intelligent merge)
118
+ - For conflicts, apply in resolved order
119
+ - Track if sync was done
120
+
121
+ b. **Perform the archive**:
122
+ ```bash
123
+ mkdir -p openspec/changes/archive
124
+ mv openspec/changes/<name> openspec/changes/archive/YYYY-MM-DD-<name>
125
+ ```
126
+
127
+ c. **Track outcome** for each change:
128
+ - Success: archived successfully
129
+ - Failed: error during archive (record error)
130
+ - Skipped: user chose not to archive (if applicable)
131
+
132
+ 9. **Display summary**
133
+
134
+ Show final results:
135
+
136
+ ```
137
+ ## Bulk Archive Complete
138
+
139
+ Archived 3 changes:
140
+ - schema-management-cli -> archive/2026-01-19-schema-management-cli/
141
+ - project-config -> archive/2026-01-19-project-config/
142
+ - add-oauth -> archive/2026-01-19-add-oauth/
143
+
144
+ Skipped 1 change:
145
+ - add-verify-skill (user chose not to archive incomplete)
146
+
147
+ Spec sync summary:
148
+ - 4 delta specs synced to main specs
149
+ - 1 conflict resolved (auth: applied both in chronological order)
150
+ ```
151
+
152
+ If any failures:
153
+ ```
154
+ Failed 1 change:
155
+ - some-change: Archive directory already exists
156
+ ```
157
+
158
+ **Conflict Resolution Examples**
159
+
160
+ Example 1: Only one implemented
161
+ ```
162
+ Conflict: specs/auth/spec.md touched by [add-oauth, add-jwt]
163
+
164
+ Checking add-oauth:
165
+ - Delta adds "OAuth Provider Integration" requirement
166
+ - Searching codebase... found src/auth/oauth.ts implementing OAuth flow
167
+
168
+ Checking add-jwt:
169
+ - Delta adds "JWT Token Handling" requirement
170
+ - Searching codebase... no JWT implementation found
171
+
172
+ Resolution: Only add-oauth is implemented. Will sync add-oauth specs only.
173
+ ```
174
+
175
+ Example 2: Both implemented
176
+ ```
177
+ Conflict: specs/api/spec.md touched by [add-rest-api, add-graphql]
178
+
179
+ Checking add-rest-api (created 2026-01-10):
180
+ - Delta adds "REST Endpoints" requirement
181
+ - Searching codebase... found src/api/rest.ts
182
+
183
+ Checking add-graphql (created 2026-01-15):
184
+ - Delta adds "GraphQL Schema" requirement
185
+ - Searching codebase... found src/api/graphql.ts
186
+
187
+ Resolution: Both implemented. Will apply add-rest-api specs first,
188
+ then add-graphql specs (chronological order, newer takes precedence).
189
+ ```
190
+
191
+ **Output On Success**
192
+
193
+ ```
194
+ ## Bulk Archive Complete
195
+
196
+ Archived N changes:
197
+ - <change-1> -> archive/YYYY-MM-DD-<change-1>/
198
+ - <change-2> -> archive/YYYY-MM-DD-<change-2>/
199
+
200
+ Spec sync summary:
201
+ - N delta specs synced to main specs
202
+ - No conflicts (or: M conflicts resolved)
203
+ ```
204
+
205
+ **Output On Partial Success**
206
+
207
+ ```
208
+ ## Bulk Archive Complete (partial)
209
+
210
+ Archived N changes:
211
+ - <change-1> -> archive/YYYY-MM-DD-<change-1>/
212
+
213
+ Skipped M changes:
214
+ - <change-2> (user chose not to archive incomplete)
215
+
216
+ Failed K changes:
217
+ - <change-3>: Archive directory already exists
218
+ ```
219
+
220
+ **Output When No Changes**
221
+
222
+ ```
223
+ ## No Changes to Archive
224
+
225
+ No active changes found. Create a new change to get started.
226
+ ```
227
+
228
+ **Guardrails**
229
+ - Allow any number of changes (1+ is fine, 2+ is the typical use case)
230
+ - Always prompt for selection, never auto-select
231
+ - Detect spec conflicts early and resolve by checking codebase
232
+ - When both changes are implemented, apply specs in chronological order
233
+ - Skip spec sync only when implementation is missing (warn user)
234
+ - Show clear per-change status before confirming
235
+ - Use single confirmation for entire batch
236
+ - Track and report all outcomes (success/skip/fail)
237
+ - Preserve .openspec.yaml when moving to archive
238
+ - Archive directory target uses current date: YYYY-MM-DD-<name>
239
+ - If archive target exists, fail that change but continue with others
.github/prompts/opsx-continue.prompt.md ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ description: Continue working on a change - create the next artifact (Experimental)
3
+ ---
4
+
5
+ Continue working on a change by creating the next artifact.
6
+
7
+ **Input**: Optionally specify a change name after `/opsx:continue` (e.g., `/opsx:continue add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
8
+
9
+ **Steps**
10
+
11
+ 1. **If no change name provided, prompt for selection**
12
+
13
+ Run `openspec list --json` to get available changes sorted by most recently modified. Then use the **AskUserQuestion tool** to let the user select which change to work on.
14
+
15
+ Present the top 3-4 most recently modified changes as options, showing:
16
+ - Change name
17
+ - Schema (from `schema` field if present, otherwise "spec-driven")
18
+ - Status (e.g., "0/5 tasks", "complete", "no tasks")
19
+ - How recently it was modified (from `lastModified` field)
20
+
21
+ Mark the most recently modified change as "(Recommended)" since it's likely what the user wants to continue.
22
+
23
+ **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
24
+
25
+ 2. **Check current status**
26
+ ```bash
27
+ openspec status --change "<name>" --json
28
+ ```
29
+ Parse the JSON to understand current state. The response includes:
30
+ - `schemaName`: The workflow schema being used (e.g., "spec-driven")
31
+ - `artifacts`: Array of artifacts with their status ("done", "ready", "blocked")
32
+ - `isComplete`: Boolean indicating if all artifacts are complete
33
+
34
+ 3. **Act based on status**:
35
+
36
+ ---
37
+
38
+ **If all artifacts are complete (`isComplete: true`)**:
39
+ - Congratulate the user
40
+ - Show final status including the schema used
41
+ - Suggest: "All artifacts created! You can now implement this change with `/opsx:apply` or archive it with `/opsx:archive`."
42
+ - STOP
43
+
44
+ ---
45
+
46
+ **If artifacts are ready to create** (status shows artifacts with `status: "ready"`):
47
+ - Pick the FIRST artifact with `status: "ready"` from the status output
48
+ - Get its instructions:
49
+ ```bash
50
+ openspec instructions <artifact-id> --change "<name>" --json
51
+ ```
52
+ - Parse the JSON. The key fields are:
53
+ - `context`: Project background (constraints for you - do NOT include in output)
54
+ - `rules`: Artifact-specific rules (constraints for you - do NOT include in output)
55
+ - `template`: The structure to use for your output file
56
+ - `instruction`: Schema-specific guidance
57
+ - `outputPath`: Where to write the artifact
58
+ - `dependencies`: Completed artifacts to read for context
59
+ - **Create the artifact file**:
60
+ - Read any completed dependency files for context
61
+ - Use `template` as the structure - fill in its sections
62
+ - Apply `context` and `rules` as constraints when writing - but do NOT copy them into the file
63
+ - Write to the output path specified in instructions
64
+ - Show what was created and what's now unlocked
65
+ - STOP after creating ONE artifact
66
+
67
+ ---
68
+
69
+ **If no artifacts are ready (all blocked)**:
70
+ - This shouldn't happen with a valid schema
71
+ - Show status and suggest checking for issues
72
+
73
+ 4. **After creating an artifact, show progress**
74
+ ```bash
75
+ openspec status --change "<name>"
76
+ ```
77
+
78
+ **Output**
79
+
80
+ After each invocation, show:
81
+ - Which artifact was created
82
+ - Schema workflow being used
83
+ - Current progress (N/M complete)
84
+ - What artifacts are now unlocked
85
+ - Prompt: "Run `/opsx:continue` to create the next artifact"
86
+
87
+ **Artifact Creation Guidelines**
88
+
89
+ The artifact types and their purpose depend on the schema. Use the `instruction` field from the instructions output to understand what to create.
90
+
91
+ Common artifact patterns:
92
+
93
+ **spec-driven schema** (proposal → specs → design → tasks):
94
+ - **proposal.md**: Ask user about the change if not clear. Fill in Why, What Changes, Capabilities, Impact.
95
+ - The Capabilities section is critical - each capability listed will need a spec file.
96
+ - **specs/<capability>/spec.md**: Create one spec per capability listed in the proposal's Capabilities section (use the capability name, not the change name).
97
+ - **design.md**: Document technical decisions, architecture, and implementation approach.
98
+ - **tasks.md**: Break down implementation into checkboxed tasks.
99
+
100
+ For other schemas, follow the `instruction` field from the CLI output.
101
+
102
+ **Guardrails**
103
+ - Create ONE artifact per invocation
104
+ - Always read dependency artifacts before creating a new one
105
+ - Never skip artifacts or create out of order
106
+ - If context is unclear, ask the user before creating
107
+ - Verify the artifact file exists after writing before marking progress
108
+ - Use the schema's artifact sequence, don't assume specific artifact names
109
+ - **IMPORTANT**: `context` and `rules` are constraints for YOU, not content for the file
110
+ - Do NOT copy `<context>`, `<rules>`, `<project_context>` blocks into the artifact
111
+ - These guide what you write, but should never appear in the output
.github/prompts/opsx-explore.prompt.md ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ description: Enter explore mode - think through ideas, investigate problems, clarify requirements
3
+ ---
4
+
5
+ Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes.
6
+
7
+ **IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing.
8
+
9
+ **This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore.
10
+
11
+ **Input**: The argument after `/opsx:explore` is whatever the user wants to think about. Could be:
12
+ - A vague idea: "real-time collaboration"
13
+ - A specific problem: "the auth system is getting unwieldy"
14
+ - A change name: "add-dark-mode" (to explore in context of that change)
15
+ - A comparison: "postgres vs sqlite for this"
16
+ - Nothing (just enter explore mode)
17
+
18
+ ---
19
+
20
+ ## The Stance
21
+
22
+ - **Curious, not prescriptive** - Ask questions that emerge naturally, don't follow a script
23
+ - **Open threads, not interrogations** - Surface multiple interesting directions and let the user follow what resonates. Don't funnel them through a single path of questions.
24
+ - **Visual** - Use ASCII diagrams liberally when they'd help clarify thinking
25
+ - **Adaptive** - Follow interesting threads, pivot when new information emerges
26
+ - **Patient** - Don't rush to conclusions, let the shape of the problem emerge
27
+ - **Grounded** - Explore the actual codebase when relevant, don't just theorize
28
+
29
+ ---
30
+
31
+ ## What You Might Do
32
+
33
+ Depending on what the user brings, you might:
34
+
35
+ **Explore the problem space**
36
+ - Ask clarifying questions that emerge from what they said
37
+ - Challenge assumptions
38
+ - Reframe the problem
39
+ - Find analogies
40
+
41
+ **Investigate the codebase**
42
+ - Map existing architecture relevant to the discussion
43
+ - Find integration points
44
+ - Identify patterns already in use
45
+ - Surface hidden complexity
46
+
47
+ **Compare options**
48
+ - Brainstorm multiple approaches
49
+ - Build comparison tables
50
+ - Sketch tradeoffs
51
+ - Recommend a path (if asked)
52
+
53
+ **Visualize**
54
+ ```
55
+ ┌─────────────────────────────────────────┐
56
+ │ Use ASCII diagrams liberally │
57
+ ├─────────────────────────────────────────┤
58
+ │ │
59
+ │ ┌────────┐ ┌────────┐ │
60
+ │ │ State │────────▶│ State │ │
61
+ │ │ A │ │ B │ │
62
+ │ └────────┘ └────────┘ │
63
+ │ │
64
+ │ System diagrams, state machines, │
65
+ │ data flows, architecture sketches, │
66
+ │ dependency graphs, comparison tables │
67
+ │ │
68
+ └─────────────────────────────────────────┘
69
+ ```
70
+
71
+ **Surface risks and unknowns**
72
+ - Identify what could go wrong
73
+ - Find gaps in understanding
74
+ - Suggest spikes or investigations
75
+
76
+ ---
77
+
78
+ ## OpenSpec Awareness
79
+
80
+ You have full context of the OpenSpec system. Use it naturally, don't force it.
81
+
82
+ ### Check for context
83
+
84
+ At the start, quickly check what exists:
85
+ ```bash
86
+ openspec list --json
87
+ ```
88
+
89
+ This tells you:
90
+ - If there are active changes
91
+ - Their names, schemas, and status
92
+ - What the user might be working on
93
+
94
+ If the user mentioned a specific change name, read its artifacts for context.
95
+
96
+ ### When no change exists
97
+
98
+ Think freely. When insights crystallize, you might offer:
99
+
100
+ - "This feels solid enough to start a change. Want me to create a proposal?"
101
+ - Or keep exploring - no pressure to formalize
102
+
103
+ ### When a change exists
104
+
105
+ If the user mentions a change or you detect one is relevant:
106
+
107
+ 1. **Read existing artifacts for context**
108
+ - `openspec/changes/<name>/proposal.md`
109
+ - `openspec/changes/<name>/design.md`
110
+ - `openspec/changes/<name>/tasks.md`
111
+ - etc.
112
+
113
+ 2. **Reference them naturally in conversation**
114
+ - "Your design mentions using Redis, but we just realized SQLite fits better..."
115
+ - "The proposal scopes this to premium users, but we're now thinking everyone..."
116
+
117
+ 3. **Offer to capture when decisions are made**
118
+
119
+ | Insight Type | Where to Capture |
120
+ |--------------|------------------|
121
+ | New requirement discovered | `specs/<capability>/spec.md` |
122
+ | Requirement changed | `specs/<capability>/spec.md` |
123
+ | Design decision made | `design.md` |
124
+ | Scope changed | `proposal.md` |
125
+ | New work identified | `tasks.md` |
126
+ | Assumption invalidated | Relevant artifact |
127
+
128
+ Example offers:
129
+ - "That's a design decision. Capture it in design.md?"
130
+ - "This is a new requirement. Add it to specs?"
131
+ - "This changes scope. Update the proposal?"
132
+
133
+ 4. **The user decides** - Offer and move on. Don't pressure. Don't auto-capture.
134
+
135
+ ---
136
+
137
+ ## What You Don't Have To Do
138
+
139
+ - Follow a script
140
+ - Ask the same questions every time
141
+ - Produce a specific artifact
142
+ - Reach a conclusion
143
+ - Stay on topic if a tangent is valuable
144
+ - Be brief (this is thinking time)
145
+
146
+ ---
147
+
148
+ ## Ending Discovery
149
+
150
+ There's no required ending. Discovery might:
151
+
152
+ - **Flow into a proposal**: "Ready to start? I can create a change proposal."
153
+ - **Result in artifact updates**: "Updated design.md with these decisions"
154
+ - **Just provide clarity**: User has what they need, moves on
155
+ - **Continue later**: "We can pick this up anytime"
156
+
157
+ When things crystallize, you might offer a summary - but it's optional. Sometimes the thinking IS the value.
158
+
159
+ ---
160
+
161
+ ## Guardrails
162
+
163
+ - **Don't implement** - Never write code or implement features. Creating OpenSpec artifacts is fine, writing application code is not.
164
+ - **Don't fake understanding** - If something is unclear, dig deeper
165
+ - **Don't rush** - Discovery is thinking time, not task time
166
+ - **Don't force structure** - Let patterns emerge naturally
167
+ - **Don't auto-capture** - Offer to save insights, don't just do it
168
+ - **Do visualize** - A good diagram is worth many paragraphs
169
+ - **Do explore the codebase** - Ground discussions in reality
170
+ - **Do question assumptions** - Including the user's and your own
.github/prompts/opsx-ff.prompt.md ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ description: Create a change and generate all artifacts needed for implementation in one go
3
+ ---
4
+
5
+ Fast-forward through artifact creation - generate everything needed to start implementation.
6
+
7
+ **Input**: The argument after `/opsx:ff` is the change name (kebab-case), OR a description of what the user wants to build.
8
+
9
+ **Steps**
10
+
11
+ 1. **If no input provided, ask what they want to build**
12
+
13
+ Use the **AskUserQuestion tool** (open-ended, no preset options) to ask:
14
+ > "What change do you want to work on? Describe what you want to build or fix."
15
+
16
+ From their description, derive a kebab-case name (e.g., "add user authentication" → `add-user-auth`).
17
+
18
+ **IMPORTANT**: Do NOT proceed without understanding what the user wants to build.
19
+
20
+ 2. **Create the change directory**
21
+ ```bash
22
+ openspec new change "<name>"
23
+ ```
24
+ This creates a scaffolded change at `openspec/changes/<name>/`.
25
+
26
+ 3. **Get the artifact build order**
27
+ ```bash
28
+ openspec status --change "<name>" --json
29
+ ```
30
+ Parse the JSON to get:
31
+ - `applyRequires`: array of artifact IDs needed before implementation (e.g., `["tasks"]`)
32
+ - `artifacts`: list of all artifacts with their status and dependencies
33
+
34
+ 4. **Create artifacts in sequence until apply-ready**
35
+
36
+ Use the **TodoWrite tool** to track progress through the artifacts.
37
+
38
+ Loop through artifacts in dependency order (artifacts with no pending dependencies first):
39
+
40
+ a. **For each artifact that is `ready` (dependencies satisfied)**:
41
+ - Get instructions:
42
+ ```bash
43
+ openspec instructions <artifact-id> --change "<name>" --json
44
+ ```
45
+ - The instructions JSON includes:
46
+ - `context`: Project background (constraints for you - do NOT include in output)
47
+ - `rules`: Artifact-specific rules (constraints for you - do NOT include in output)
48
+ - `template`: The structure to use for your output file
49
+ - `instruction`: Schema-specific guidance for this artifact type
50
+ - `outputPath`: Where to write the artifact
51
+ - `dependencies`: Completed artifacts to read for context
52
+ - Read any completed dependency files for context
53
+ - Create the artifact file using `template` as the structure
54
+ - Apply `context` and `rules` as constraints - but do NOT copy them into the file
55
+ - Show brief progress: "✓ Created <artifact-id>"
56
+
57
+ b. **Continue until all `applyRequires` artifacts are complete**
58
+ - After creating each artifact, re-run `openspec status --change "<name>" --json`
59
+ - Check if every artifact ID in `applyRequires` has `status: "done"` in the artifacts array
60
+ - Stop when all `applyRequires` artifacts are done
61
+
62
+ c. **If an artifact requires user input** (unclear context):
63
+ - Use **AskUserQuestion tool** to clarify
64
+ - Then continue with creation
65
+
66
+ 5. **Show final status**
67
+ ```bash
68
+ openspec status --change "<name>"
69
+ ```
70
+
71
+ **Output**
72
+
73
+ After completing all artifacts, summarize:
74
+ - Change name and location
75
+ - List of artifacts created with brief descriptions
76
+ - What's ready: "All artifacts created! Ready for implementation."
77
+ - Prompt: "Run `/opsx:apply` to start implementing."
78
+
79
+ **Artifact Creation Guidelines**
80
+
81
+ - Follow the `instruction` field from `openspec instructions` for each artifact type
82
+ - The schema defines what each artifact should contain - follow it
83
+ - Read dependency artifacts for context before creating new ones
84
+ - Use `template` as the structure for your output file - fill in its sections
85
+ - **IMPORTANT**: `context` and `rules` are constraints for YOU, not content for the file
86
+ - Do NOT copy `<context>`, `<rules>`, `<project_context>` blocks into the artifact
87
+ - These guide what you write, but should never appear in the output
88
+
89
+ **Guardrails**
90
+ - Create ALL artifacts needed for implementation (as defined by schema's `apply.requires`)
91
+ - Always read dependency artifacts before creating a new one
92
+ - If context is critically unclear, ask the user - but prefer making reasonable decisions to keep momentum
93
+ - If a change with that name already exists, ask if user wants to continue it or create a new one
94
+ - Verify each artifact file exists after writing before proceeding to next
.github/prompts/opsx-new.prompt.md ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ description: Start a new change using the experimental artifact workflow (OPSX)
3
+ ---
4
+
5
+ Start a new change using the experimental artifact-driven approach.
6
+
7
+ **Input**: The argument after `/opsx:new` is the change name (kebab-case), OR a description of what the user wants to build.
8
+
9
+ **Steps**
10
+
11
+ 1. **If no input provided, ask what they want to build**
12
+
13
+ Use the **AskUserQuestion tool** (open-ended, no preset options) to ask:
14
+ > "What change do you want to work on? Describe what you want to build or fix."
15
+
16
+ From their description, derive a kebab-case name (e.g., "add user authentication" → `add-user-auth`).
17
+
18
+ **IMPORTANT**: Do NOT proceed without understanding what the user wants to build.
19
+
20
+ 2. **Determine the workflow schema**
21
+
22
+ Use the default schema (omit `--schema`) unless the user explicitly requests a different workflow.
23
+
24
+ **Use a different schema only if the user mentions:**
25
+ - A specific schema name → use `--schema <name>`
26
+ - "show workflows" or "what workflows" → run `openspec schemas --json` and let them choose
27
+
28
+ **Otherwise**: Omit `--schema` to use the default.
29
+
30
+ 3. **Create the change directory**
31
+ ```bash
32
+ openspec new change "<name>"
33
+ ```
34
+ Add `--schema <name>` only if the user requested a specific workflow.
35
+ This creates a scaffolded change at `openspec/changes/<name>/` with the selected schema.
36
+
37
+ 4. **Show the artifact status**
38
+ ```bash
39
+ openspec status --change "<name>"
40
+ ```
41
+ This shows which artifacts need to be created and which are ready (dependencies satisfied).
42
+
43
+ 5. **Get instructions for the first artifact**
44
+ The first artifact depends on the schema. Check the status output to find the first artifact with status "ready".
45
+ ```bash
46
+ openspec instructions <first-artifact-id> --change "<name>"
47
+ ```
48
+ This outputs the template and context for creating the first artifact.
49
+
50
+ 6. **STOP and wait for user direction**
51
+
52
+ **Output**
53
+
54
+ After completing the steps, summarize:
55
+ - Change name and location
56
+ - Schema/workflow being used and its artifact sequence
57
+ - Current status (0/N artifacts complete)
58
+ - The template for the first artifact
59
+ - Prompt: "Ready to create the first artifact? Run `/opsx:continue` or just describe what this change is about and I'll draft it."
60
+
61
+ **Guardrails**
62
+ - Do NOT create any artifacts yet - just show the instructions
63
+ - Do NOT advance beyond showing the first artifact template
64
+ - If the name is invalid (not kebab-case), ask for a valid name
65
+ - If a change with that name already exists, suggest using `/opsx:continue` instead
66
+ - Pass --schema if using a non-default workflow
.github/prompts/opsx-onboard.prompt.md ADDED
@@ -0,0 +1,547 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ description: Guided onboarding - walk through a complete OpenSpec workflow cycle with narration
3
+ ---
4
+
5
+ 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.
6
+
7
+ ---
8
+
9
+ ## Preflight
10
+
11
+ Before starting, check if the OpenSpec CLI is installed:
12
+
13
+ ```bash
14
+ # Unix/macOS
15
+ openspec --version 2>&1 || echo "CLI_NOT_INSTALLED"
16
+ # Windows (PowerShell)
17
+ # if (Get-Command openspec -ErrorAction SilentlyContinue) { openspec --version } else { echo "CLI_NOT_INSTALLED" }
18
+ ```
19
+
20
+ **If CLI not installed:**
21
+ > OpenSpec CLI is not installed. Install it first, then come back to `/opsx:onboard`.
22
+
23
+ Stop here if not installed.
24
+
25
+ ---
26
+
27
+ ## Phase 1: Welcome
28
+
29
+ Display:
30
+
31
+ ```
32
+ ## Welcome to OpenSpec!
33
+
34
+ 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.
35
+
36
+ **What we'll do:**
37
+ 1. Pick a small, real task in your codebase
38
+ 2. Explore the problem briefly
39
+ 3. Create a change (the container for our work)
40
+ 4. Build the artifacts: proposal → specs → design → tasks
41
+ 5. Implement the tasks
42
+ 6. Archive the completed change
43
+
44
+ **Time:** ~15-20 minutes
45
+
46
+ Let's start by finding something to work on.
47
+ ```
48
+
49
+ ---
50
+
51
+ ## Phase 2: Task Selection
52
+
53
+ ### Codebase Analysis
54
+
55
+ Scan the codebase for small improvement opportunities. Look for:
56
+
57
+ 1. **TODO/FIXME comments** - Search for `TODO`, `FIXME`, `HACK`, `XXX` in code files
58
+ 2. **Missing error handling** - `catch` blocks that swallow errors, risky operations without try-catch
59
+ 3. **Functions without tests** - Cross-reference `src/` with test directories
60
+ 4. **Type issues** - `any` types in TypeScript files (`: any`, `as any`)
61
+ 5. **Debug artifacts** - `console.log`, `console.debug`, `debugger` statements in non-debug code
62
+ 6. **Missing validation** - User input handlers without validation
63
+
64
+ Also check recent git activity:
65
+ ```bash
66
+ # Unix/macOS
67
+ git log --oneline -10 2>/dev/null || echo "No git history"
68
+ # Windows (PowerShell)
69
+ # git log --oneline -10 2>$null; if ($LASTEXITCODE -ne 0) { echo "No git history" }
70
+ ```
71
+
72
+ ### Present Suggestions
73
+
74
+ From your analysis, present 3-4 specific suggestions:
75
+
76
+ ```
77
+ ## Task Suggestions
78
+
79
+ Based on scanning your codebase, here are some good starter tasks:
80
+
81
+ **1. [Most promising task]**
82
+ Location: `src/path/to/file.ts:42`
83
+ Scope: ~1-2 files, ~20-30 lines
84
+ Why it's good: [brief reason]
85
+
86
+ **2. [Second task]**
87
+ Location: `src/another/file.ts`
88
+ Scope: ~1 file, ~15 lines
89
+ Why it's good: [brief reason]
90
+
91
+ **3. [Third task]**
92
+ Location: [location]
93
+ Scope: [estimate]
94
+ Why it's good: [brief reason]
95
+
96
+ **4. Something else?**
97
+ Tell me what you'd like to work on.
98
+
99
+ Which task interests you? (Pick a number or describe your own)
100
+ ```
101
+
102
+ **If nothing found:** Fall back to asking what the user wants to build:
103
+ > I didn't find obvious quick wins in your codebase. What's something small you've been meaning to add or fix?
104
+
105
+ ### Scope Guardrail
106
+
107
+ If the user picks or describes something too large (major feature, multi-day work):
108
+
109
+ ```
110
+ That's a valuable task, but it's probably larger than ideal for your first OpenSpec run-through.
111
+
112
+ For learning the workflow, smaller is better—it lets you see the full cycle without getting stuck in implementation details.
113
+
114
+ **Options:**
115
+ 1. **Slice it smaller** - What's the smallest useful piece of [their task]? Maybe just [specific slice]?
116
+ 2. **Pick something else** - One of the other suggestions, or a different small task?
117
+ 3. **Do it anyway** - If you really want to tackle this, we can. Just know it'll take longer.
118
+
119
+ What would you prefer?
120
+ ```
121
+
122
+ Let the user override if they insist—this is a soft guardrail.
123
+
124
+ ---
125
+
126
+ ## Phase 3: Explore Demo
127
+
128
+ Once a task is selected, briefly demonstrate explore mode:
129
+
130
+ ```
131
+ Before we create a change, let me quickly show you **explore mode**—it's how you think through problems before committing to a direction.
132
+ ```
133
+
134
+ Spend 1-2 minutes investigating the relevant code:
135
+ - Read the file(s) involved
136
+ - Draw a quick ASCII diagram if it helps
137
+ - Note any considerations
138
+
139
+ ```
140
+ ## Quick Exploration
141
+
142
+ [Your brief analysis—what you found, any considerations]
143
+
144
+ ┌─────────────────────────────────────────┐
145
+ │ [Optional: ASCII diagram if helpful] │
146
+ └─────────────────────────────────────────┘
147
+
148
+ 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.
149
+
150
+ Now let's create a change to hold our work.
151
+ ```
152
+
153
+ **PAUSE** - Wait for user acknowledgment before proceeding.
154
+
155
+ ---
156
+
157
+ ## Phase 4: Create the Change
158
+
159
+ **EXPLAIN:**
160
+ ```
161
+ ## Creating a Change
162
+
163
+ A "change" in OpenSpec is a container for all the thinking and planning around a piece of work. It lives in `openspec/changes/<name>/` and holds your artifacts—proposal, specs, design, tasks.
164
+
165
+ Let me create one for our task.
166
+ ```
167
+
168
+ **DO:** Create the change with a derived kebab-case name:
169
+ ```bash
170
+ openspec new change "<derived-name>"
171
+ ```
172
+
173
+ **SHOW:**
174
+ ```
175
+ Created: `openspec/changes/<name>/`
176
+
177
+ The folder structure:
178
+ ```
179
+ openspec/changes/<name>/
180
+ ├── proposal.md ← Why we're doing this (empty, we'll fill it)
181
+ ├── design.md ← How we'll build it (empty)
182
+ ├── specs/ ← Detailed requirements (empty)
183
+ └── tasks.md ← Implementation checklist (empty)
184
+ ```
185
+
186
+ Now let's fill in the first artifact—the proposal.
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Phase 5: Proposal
192
+
193
+ **EXPLAIN:**
194
+ ```
195
+ ## The Proposal
196
+
197
+ 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.
198
+
199
+ I'll draft one based on our task.
200
+ ```
201
+
202
+ **DO:** Draft the proposal content (don't save yet):
203
+
204
+ ```
205
+ Here's a draft proposal:
206
+
207
+ ---
208
+
209
+ ## Why
210
+
211
+ [1-2 sentences explaining the problem/opportunity]
212
+
213
+ ## What Changes
214
+
215
+ [Bullet points of what will be different]
216
+
217
+ ## Capabilities
218
+
219
+ ### New Capabilities
220
+ - `<capability-name>`: [brief description]
221
+
222
+ ### Modified Capabilities
223
+ <!-- If modifying existing behavior -->
224
+
225
+ ## Impact
226
+
227
+ - `src/path/to/file.ts`: [what changes]
228
+ - [other files if applicable]
229
+
230
+ ---
231
+
232
+ Does this capture the intent? I can adjust before we save it.
233
+ ```
234
+
235
+ **PAUSE** - Wait for user approval/feedback.
236
+
237
+ After approval, save the proposal:
238
+ ```bash
239
+ openspec instructions proposal --change "<name>" --json
240
+ ```
241
+ Then write the content to `openspec/changes/<name>/proposal.md`.
242
+
243
+ ```
244
+ Proposal saved. This is your "why" document—you can always come back and refine it as understanding evolves.
245
+
246
+ Next up: specs.
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Phase 6: Specs
252
+
253
+ **EXPLAIN:**
254
+ ```
255
+ ## Specs
256
+
257
+ Specs define **what** we're building in precise, testable terms. They use a requirement/scenario format that makes expected behavior crystal clear.
258
+
259
+ For a small task like this, we might only need one spec file.
260
+ ```
261
+
262
+ **DO:** Create the spec file:
263
+ ```bash
264
+ # Unix/macOS
265
+ mkdir -p openspec/changes/<name>/specs/<capability-name>
266
+ # Windows (PowerShell)
267
+ # New-Item -ItemType Directory -Force -Path "openspec/changes/<name>/specs/<capability-name>"
268
+ ```
269
+
270
+ Draft the spec content:
271
+
272
+ ```
273
+ Here's the spec:
274
+
275
+ ---
276
+
277
+ ## ADDED Requirements
278
+
279
+ ### Requirement: <Name>
280
+
281
+ <Description of what the system should do>
282
+
283
+ #### Scenario: <Scenario name>
284
+
285
+ - **WHEN** <trigger condition>
286
+ - **THEN** <expected outcome>
287
+ - **AND** <additional outcome if needed>
288
+
289
+ ---
290
+
291
+ This format—WHEN/THEN/AND—makes requirements testable. You can literally read them as test cases.
292
+ ```
293
+
294
+ Save to `openspec/changes/<name>/specs/<capability>/spec.md`.
295
+
296
+ ---
297
+
298
+ ## Phase 7: Design
299
+
300
+ **EXPLAIN:**
301
+ ```
302
+ ## Design
303
+
304
+ The design captures **how** we'll build it—technical decisions, tradeoffs, approach.
305
+
306
+ For small changes, this might be brief. That's fine—not every change needs deep design discussion.
307
+ ```
308
+
309
+ **DO:** Draft design.md:
310
+
311
+ ```
312
+ Here's the design:
313
+
314
+ ---
315
+
316
+ ## Context
317
+
318
+ [Brief context about the current state]
319
+
320
+ ## Goals / Non-Goals
321
+
322
+ **Goals:**
323
+ - [What we're trying to achieve]
324
+
325
+ **Non-Goals:**
326
+ - [What's explicitly out of scope]
327
+
328
+ ## Decisions
329
+
330
+ ### Decision 1: [Key decision]
331
+
332
+ [Explanation of approach and rationale]
333
+
334
+ ---
335
+
336
+ For a small task, this captures the key decisions without over-engineering.
337
+ ```
338
+
339
+ Save to `openspec/changes/<name>/design.md`.
340
+
341
+ ---
342
+
343
+ ## Phase 8: Tasks
344
+
345
+ **EXPLAIN:**
346
+ ```
347
+ ## Tasks
348
+
349
+ Finally, we break the work into implementation tasks—checkboxes that drive the apply phase.
350
+
351
+ These should be small, clear, and in logical order.
352
+ ```
353
+
354
+ **DO:** Generate tasks based on specs and design:
355
+
356
+ ```
357
+ Here are the implementation tasks:
358
+
359
+ ---
360
+
361
+ ## 1. [Category or file]
362
+
363
+ - [ ] 1.1 [Specific task]
364
+ - [ ] 1.2 [Specific task]
365
+
366
+ ## 2. Verify
367
+
368
+ - [ ] 2.1 [Verification step]
369
+
370
+ ---
371
+
372
+ Each checkbox becomes a unit of work in the apply phase. Ready to implement?
373
+ ```
374
+
375
+ **PAUSE** - Wait for user to confirm they're ready to implement.
376
+
377
+ Save to `openspec/changes/<name>/tasks.md`.
378
+
379
+ ---
380
+
381
+ ## Phase 9: Apply (Implementation)
382
+
383
+ **EXPLAIN:**
384
+ ```
385
+ ## Implementation
386
+
387
+ 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.
388
+ ```
389
+
390
+ **DO:** For each task:
391
+
392
+ 1. Announce: "Working on task N: [description]"
393
+ 2. Implement the change in the codebase
394
+ 3. Reference specs/design naturally: "The spec says X, so I'm doing Y"
395
+ 4. Mark complete in tasks.md: `- [ ]` → `- [x]`
396
+ 5. Brief status: "✓ Task N complete"
397
+
398
+ Keep narration light—don't over-explain every line of code.
399
+
400
+ After all tasks:
401
+
402
+ ```
403
+ ## Implementation Complete
404
+
405
+ All tasks done:
406
+ - [x] Task 1
407
+ - [x] Task 2
408
+ - [x] ...
409
+
410
+ The change is implemented! One more step—let's archive it.
411
+ ```
412
+
413
+ ---
414
+
415
+ ## Phase 10: Archive
416
+
417
+ **EXPLAIN:**
418
+ ```
419
+ ## Archiving
420
+
421
+ When a change is complete, we archive it. This moves it from `openspec/changes/` to `openspec/changes/archive/YYYY-MM-DD-<name>/`.
422
+
423
+ Archived changes become your project's decision history—you can always find them later to understand why something was built a certain way.
424
+ ```
425
+
426
+ **DO:**
427
+ ```bash
428
+ openspec archive "<name>"
429
+ ```
430
+
431
+ **SHOW:**
432
+ ```
433
+ Archived to: `openspec/changes/archive/YYYY-MM-DD-<name>/`
434
+
435
+ The change is now part of your project's history. The code is in your codebase, the decision record is preserved.
436
+ ```
437
+
438
+ ---
439
+
440
+ ## Phase 11: Recap & Next Steps
441
+
442
+ ```
443
+ ## Congratulations!
444
+
445
+ You just completed a full OpenSpec cycle:
446
+
447
+ 1. **Explore** - Thought through the problem
448
+ 2. **New** - Created a change container
449
+ 3. **Proposal** - Captured WHY
450
+ 4. **Specs** - Defined WHAT in detail
451
+ 5. **Design** - Decided HOW
452
+ 6. **Tasks** - Broke it into steps
453
+ 7. **Apply** - Implemented the work
454
+ 8. **Archive** - Preserved the record
455
+
456
+ This same rhythm works for any size change—a small fix or a major feature.
457
+
458
+ ---
459
+
460
+ ## Command Reference
461
+
462
+ **Core workflow:**
463
+
464
+ | Command | What it does |
465
+ |---------|--------------|
466
+ | `/opsx:propose` | Create a change and generate all artifacts |
467
+ | `/opsx:explore` | Think through problems before/during work |
468
+ | `/opsx:apply` | Implement tasks from a change |
469
+ | `/opsx:archive` | Archive a completed change |
470
+
471
+ **Additional commands:**
472
+
473
+ | Command | What it does |
474
+ |---------|--------------|
475
+ | `/opsx:new` | Start a new change, step through artifacts one at a time |
476
+ | `/opsx:continue` | Continue working on an existing change |
477
+ | `/opsx:ff` | Fast-forward: create all artifacts at once |
478
+ | `/opsx:verify` | Verify implementation matches artifacts |
479
+
480
+ ---
481
+
482
+ ## What's Next?
483
+
484
+ Try `/opsx:propose` on something you actually want to build. You've got the rhythm now!
485
+ ```
486
+
487
+ ---
488
+
489
+ ## Graceful Exit Handling
490
+
491
+ ### User wants to stop mid-way
492
+
493
+ If the user says they need to stop, want to pause, or seem disengaged:
494
+
495
+ ```
496
+ No problem! Your change is saved at `openspec/changes/<name>/`.
497
+
498
+ To pick up where we left off later:
499
+ - `/opsx:continue <name>` - Resume artifact creation
500
+ - `/opsx:apply <name>` - Jump to implementation (if tasks exist)
501
+
502
+ The work won't be lost. Come back whenever you're ready.
503
+ ```
504
+
505
+ Exit gracefully without pressure.
506
+
507
+ ### User just wants command reference
508
+
509
+ If the user says they just want to see the commands or skip the tutorial:
510
+
511
+ ```
512
+ ## OpenSpec Quick Reference
513
+
514
+ **Core workflow:**
515
+
516
+ | Command | What it does |
517
+ |---------|--------------|
518
+ | `/opsx:propose <name>` | Create a change and generate all artifacts |
519
+ | `/opsx:explore` | Think through problems (no code changes) |
520
+ | `/opsx:apply <name>` | Implement tasks |
521
+ | `/opsx:archive <name>` | Archive when done |
522
+
523
+ **Additional commands:**
524
+
525
+ | Command | What it does |
526
+ |---------|--------------|
527
+ | `/opsx:new <name>` | Start a new change, step by step |
528
+ | `/opsx:continue <name>` | Continue an existing change |
529
+ | `/opsx:ff <name>` | Fast-forward: all artifacts at once |
530
+ | `/opsx:verify <name>` | Verify implementation |
531
+
532
+ Try `/opsx:propose` to start your first change.
533
+ ```
534
+
535
+ Exit gracefully.
536
+
537
+ ---
538
+
539
+ ## Guardrails
540
+
541
+ - **Follow the EXPLAIN → DO → SHOW → PAUSE pattern** at key transitions (after explore, after proposal draft, after tasks, after archive)
542
+ - **Keep narration light** during implementation—teach without lecturing
543
+ - **Don't skip phases** even if the change is small—the goal is teaching the workflow
544
+ - **Pause for acknowledgment** at marked points, but don't over-pause
545
+ - **Handle exits gracefully**—never pressure the user to continue
546
+ - **Use real codebase tasks**—don't simulate or use fake examples
547
+ - **Adjust scope gently**—guide toward smaller tasks but respect user choice
.github/prompts/opsx-sync.prompt.md ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ description: Sync delta specs from a change to main specs
3
+ ---
4
+
5
+ Sync delta specs from a change to main specs.
6
+
7
+ This is an **agent-driven** operation - you will read delta specs and directly edit main specs to apply the changes. This allows intelligent merging (e.g., adding a scenario without copying the entire requirement).
8
+
9
+ **Input**: Optionally specify a change name after `/opsx:sync` (e.g., `/opsx:sync add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
10
+
11
+ **Steps**
12
+
13
+ 1. **If no change name provided, prompt for selection**
14
+
15
+ Run `openspec list --json` to get available changes. Use the **AskUserQuestion tool** to let the user select.
16
+
17
+ Show changes that have delta specs (under `specs/` directory).
18
+
19
+ **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
20
+
21
+ 2. **Find delta specs**
22
+
23
+ Look for delta spec files in `openspec/changes/<name>/specs/*/spec.md`.
24
+
25
+ Each delta spec file contains sections like:
26
+ - `## ADDED Requirements` - New requirements to add
27
+ - `## MODIFIED Requirements` - Changes to existing requirements
28
+ - `## REMOVED Requirements` - Requirements to remove
29
+ - `## RENAMED Requirements` - Requirements to rename (FROM:/TO: format)
30
+
31
+ If no delta specs found, inform user and stop.
32
+
33
+ 3. **For each delta spec, apply changes to main specs**
34
+
35
+ For each capability with a delta spec at `openspec/changes/<name>/specs/<capability>/spec.md`:
36
+
37
+ a. **Read the delta spec** to understand the intended changes
38
+
39
+ b. **Read the main spec** at `openspec/specs/<capability>/spec.md` (may not exist yet)
40
+
41
+ c. **Apply changes intelligently**:
42
+
43
+ **ADDED Requirements:**
44
+ - If requirement doesn't exist in main spec → add it
45
+ - If requirement already exists → update it to match (treat as implicit MODIFIED)
46
+
47
+ **MODIFIED Requirements:**
48
+ - Find the requirement in main spec
49
+ - Apply the changes - this can be:
50
+ - Adding new scenarios (don't need to copy existing ones)
51
+ - Modifying existing scenarios
52
+ - Changing the requirement description
53
+ - Preserve scenarios/content not mentioned in the delta
54
+
55
+ **REMOVED Requirements:**
56
+ - Remove the entire requirement block from main spec
57
+
58
+ **RENAMED Requirements:**
59
+ - Find the FROM requirement, rename to TO
60
+
61
+ d. **Create new main spec** if capability doesn't exist yet:
62
+ - Create `openspec/specs/<capability>/spec.md`
63
+ - Add Purpose section (can be brief, mark as TBD)
64
+ - Add Requirements section with the ADDED requirements
65
+
66
+ 4. **Show summary**
67
+
68
+ After applying all changes, summarize:
69
+ - Which capabilities were updated
70
+ - What changes were made (requirements added/modified/removed/renamed)
71
+
72
+ **Delta Spec Format Reference**
73
+
74
+ ```markdown
75
+ ## ADDED Requirements
76
+
77
+ ### Requirement: New Feature
78
+ The system SHALL do something new.
79
+
80
+ #### Scenario: Basic case
81
+ - **WHEN** user does X
82
+ - **THEN** system does Y
83
+
84
+ ## MODIFIED Requirements
85
+
86
+ ### Requirement: Existing Feature
87
+ #### Scenario: New scenario to add
88
+ - **WHEN** user does A
89
+ - **THEN** system does B
90
+
91
+ ## REMOVED Requirements
92
+
93
+ ### Requirement: Deprecated Feature
94
+
95
+ ## RENAMED Requirements
96
+
97
+ - FROM: `### Requirement: Old Name`
98
+ - TO: `### Requirement: New Name`
99
+ ```
100
+
101
+ **Key Principle: Intelligent Merging**
102
+
103
+ Unlike programmatic merging, you can apply **partial updates**:
104
+ - To add a scenario, just include that scenario under MODIFIED - don't copy existing scenarios
105
+ - The delta represents *intent*, not a wholesale replacement
106
+ - Use your judgment to merge changes sensibly
107
+
108
+ **Output On Success**
109
+
110
+ ```
111
+ ## Specs Synced: <change-name>
112
+
113
+ Updated main specs:
114
+
115
+ **<capability-1>**:
116
+ - Added requirement: "New Feature"
117
+ - Modified requirement: "Existing Feature" (added 1 scenario)
118
+
119
+ **<capability-2>**:
120
+ - Created new spec file
121
+ - Added requirement: "Another Feature"
122
+
123
+ Main specs are now updated. The change remains active - archive when implementation is complete.
124
+ ```
125
+
126
+ **Guardrails**
127
+ - Read both delta and main specs before making changes
128
+ - Preserve existing content not mentioned in delta
129
+ - If something is unclear, ask for clarification
130
+ - Show what you're changing as you go
131
+ - The operation should be idempotent - running twice should give same result
.github/prompts/opsx-verify.prompt.md ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ description: Verify implementation matches change artifacts before archiving
3
+ ---
4
+
5
+ Verify that an implementation matches the change artifacts (specs, tasks, design).
6
+
7
+ **Input**: Optionally specify a change name after `/opsx:verify` (e.g., `/opsx:verify add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
8
+
9
+ **Steps**
10
+
11
+ 1. **If no change name provided, prompt for selection**
12
+
13
+ Run `openspec list --json` to get available changes. Use the **AskUserQuestion tool** to let the user select.
14
+
15
+ Show changes that have implementation tasks (tasks artifact exists).
16
+ Include the schema used for each change if available.
17
+ Mark changes with incomplete tasks as "(In Progress)".
18
+
19
+ **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
20
+
21
+ 2. **Check status to understand the schema**
22
+ ```bash
23
+ openspec status --change "<name>" --json
24
+ ```
25
+ Parse the JSON to understand:
26
+ - `schemaName`: The workflow being used (e.g., "spec-driven")
27
+ - Which artifacts exist for this change
28
+
29
+ 3. **Get the change directory and load artifacts**
30
+
31
+ ```bash
32
+ openspec instructions apply --change "<name>" --json
33
+ ```
34
+
35
+ This returns the change directory and context files. Read all available artifacts from `contextFiles`.
36
+
37
+ 4. **Initialize verification report structure**
38
+
39
+ Create a report structure with three dimensions:
40
+ - **Completeness**: Track tasks and spec coverage
41
+ - **Correctness**: Track requirement implementation and scenario coverage
42
+ - **Coherence**: Track design adherence and pattern consistency
43
+
44
+ Each dimension can have CRITICAL, WARNING, or SUGGESTION issues.
45
+
46
+ 5. **Verify Completeness**
47
+
48
+ **Task Completion**:
49
+ - If tasks.md exists in contextFiles, read it
50
+ - Parse checkboxes: `- [ ]` (incomplete) vs `- [x]` (complete)
51
+ - Count complete vs total tasks
52
+ - If incomplete tasks exist:
53
+ - Add CRITICAL issue for each incomplete task
54
+ - Recommendation: "Complete task: <description>" or "Mark as done if already implemented"
55
+
56
+ **Spec Coverage**:
57
+ - If delta specs exist in `openspec/changes/<name>/specs/`:
58
+ - Extract all requirements (marked with "### Requirement:")
59
+ - For each requirement:
60
+ - Search codebase for keywords related to the requirement
61
+ - Assess if implementation likely exists
62
+ - If requirements appear unimplemented:
63
+ - Add CRITICAL issue: "Requirement not found: <requirement name>"
64
+ - Recommendation: "Implement requirement X: <description>"
65
+
66
+ 6. **Verify Correctness**
67
+
68
+ **Requirement Implementation Mapping**:
69
+ - For each requirement from delta specs:
70
+ - Search codebase for implementation evidence
71
+ - If found, note file paths and line ranges
72
+ - Assess if implementation matches requirement intent
73
+ - If divergence detected:
74
+ - Add WARNING: "Implementation may diverge from spec: <details>"
75
+ - Recommendation: "Review <file>:<lines> against requirement X"
76
+
77
+ **Scenario Coverage**:
78
+ - For each scenario in delta specs (marked with "#### Scenario:"):
79
+ - Check if conditions are handled in code
80
+ - Check if tests exist covering the scenario
81
+ - If scenario appears uncovered:
82
+ - Add WARNING: "Scenario not covered: <scenario name>"
83
+ - Recommendation: "Add test or implementation for scenario: <description>"
84
+
85
+ 7. **Verify Coherence**
86
+
87
+ **Design Adherence**:
88
+ - If design.md exists in contextFiles:
89
+ - Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:")
90
+ - Verify implementation follows those decisions
91
+ - If contradiction detected:
92
+ - Add WARNING: "Design decision not followed: <decision>"
93
+ - Recommendation: "Update implementation or revise design.md to match reality"
94
+ - If no design.md: Skip design adherence check, note "No design.md to verify against"
95
+
96
+ **Code Pattern Consistency**:
97
+ - Review new code for consistency with project patterns
98
+ - Check file naming, directory structure, coding style
99
+ - If significant deviations found:
100
+ - Add SUGGESTION: "Code pattern deviation: <details>"
101
+ - Recommendation: "Consider following project pattern: <example>"
102
+
103
+ 8. **Generate Verification Report**
104
+
105
+ **Summary Scorecard**:
106
+ ```
107
+ ## Verification Report: <change-name>
108
+
109
+ ### Summary
110
+ | Dimension | Status |
111
+ |--------------|------------------|
112
+ | Completeness | X/Y tasks, N reqs|
113
+ | Correctness | M/N reqs covered |
114
+ | Coherence | Followed/Issues |
115
+ ```
116
+
117
+ **Issues by Priority**:
118
+
119
+ 1. **CRITICAL** (Must fix before archive):
120
+ - Incomplete tasks
121
+ - Missing requirement implementations
122
+ - Each with specific, actionable recommendation
123
+
124
+ 2. **WARNING** (Should fix):
125
+ - Spec/design divergences
126
+ - Missing scenario coverage
127
+ - Each with specific recommendation
128
+
129
+ 3. **SUGGESTION** (Nice to fix):
130
+ - Pattern inconsistencies
131
+ - Minor improvements
132
+ - Each with specific recommendation
133
+
134
+ **Final Assessment**:
135
+ - If CRITICAL issues: "X critical issue(s) found. Fix before archiving."
136
+ - If only warnings: "No critical issues. Y warning(s) to consider. Ready for archive (with noted improvements)."
137
+ - If all clear: "All checks passed. Ready for archive."
138
+
139
+ **Verification Heuristics**
140
+
141
+ - **Completeness**: Focus on objective checklist items (checkboxes, requirements list)
142
+ - **Correctness**: Use keyword search, file path analysis, reasonable inference - don't require perfect certainty
143
+ - **Coherence**: Look for glaring inconsistencies, don't nitpick style
144
+ - **False Positives**: When uncertain, prefer SUGGESTION over WARNING, WARNING over CRITICAL
145
+ - **Actionability**: Every issue must have a specific recommendation with file/line references where applicable
146
+
147
+ **Graceful Degradation**
148
+
149
+ - If only tasks.md exists: verify task completion only, skip spec/design checks
150
+ - If tasks + specs exist: verify completeness and correctness, skip design
151
+ - If full artifacts: verify all three dimensions
152
+ - Always note which checks were skipped and why
153
+
154
+ **Output Format**
155
+
156
+ Use clear markdown with:
157
+ - Table for summary scorecard
158
+ - Grouped lists for issues (CRITICAL/WARNING/SUGGESTION)
159
+ - Code references in format: `file.ts:123`
160
+ - Specific, actionable recommendations
161
+ - No vague suggestions like "consider reviewing"
.github/skills/openspec-apply-change/SKILL.md ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: openspec-apply-change
3
+ description: Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.
4
+ license: MIT
5
+ compatibility: Requires openspec CLI.
6
+ metadata:
7
+ author: openspec
8
+ version: "1.0"
9
+ generatedBy: "1.2.0"
10
+ ---
11
+
12
+ Implement tasks from an OpenSpec change.
13
+
14
+ **Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
15
+
16
+ **Steps**
17
+
18
+ 1. **Select the change**
19
+
20
+ If a name is provided, use it. Otherwise:
21
+ - Infer from conversation context if the user mentioned a change
22
+ - Auto-select if only one active change exists
23
+ - If ambiguous, run `openspec list --json` to get available changes and use the **AskUserQuestion tool** to let the user select
24
+
25
+ Always announce: "Using change: <name>" and how to override (e.g., `/opsx:apply <other>`).
26
+
27
+ 2. **Check status to understand the schema**
28
+ ```bash
29
+ openspec status --change "<name>" --json
30
+ ```
31
+ Parse the JSON to understand:
32
+ - `schemaName`: The workflow being used (e.g., "spec-driven")
33
+ - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others)
34
+
35
+ 3. **Get apply instructions**
36
+
37
+ ```bash
38
+ openspec instructions apply --change "<name>" --json
39
+ ```
40
+
41
+ This returns:
42
+ - Context file paths (varies by schema - could be proposal/specs/design/tasks or spec/tests/implementation/docs)
43
+ - Progress (total, complete, remaining)
44
+ - Task list with status
45
+ - Dynamic instruction based on current state
46
+
47
+ **Handle states:**
48
+ - If `state: "blocked"` (missing artifacts): show message, suggest using openspec-continue-change
49
+ - If `state: "all_done"`: congratulate, suggest archive
50
+ - Otherwise: proceed to implementation
51
+
52
+ 4. **Read context files**
53
+
54
+ Read the files listed in `contextFiles` from the apply instructions output.
55
+ The files depend on the schema being used:
56
+ - **spec-driven**: proposal, specs, design, tasks
57
+ - Other schemas: follow the contextFiles from CLI output
58
+
59
+ 5. **Show current progress**
60
+
61
+ Display:
62
+ - Schema being used
63
+ - Progress: "N/M tasks complete"
64
+ - Remaining tasks overview
65
+ - Dynamic instruction from CLI
66
+
67
+ 6. **Implement tasks (loop until done or blocked)**
68
+
69
+ For each pending task:
70
+ - Show which task is being worked on
71
+ - Make the code changes required
72
+ - Keep changes minimal and focused
73
+ - Mark task complete in the tasks file: `- [ ]` → `- [x]`
74
+ - Continue to next task
75
+
76
+ **Pause if:**
77
+ - Task is unclear → ask for clarification
78
+ - Implementation reveals a design issue → suggest updating artifacts
79
+ - Error or blocker encountered → report and wait for guidance
80
+ - User interrupts
81
+
82
+ 7. **On completion or pause, show status**
83
+
84
+ Display:
85
+ - Tasks completed this session
86
+ - Overall progress: "N/M tasks complete"
87
+ - If all done: suggest archive
88
+ - If paused: explain why and wait for guidance
89
+
90
+ **Output During Implementation**
91
+
92
+ ```
93
+ ## Implementing: <change-name> (schema: <schema-name>)
94
+
95
+ Working on task 3/7: <task description>
96
+ [...implementation happening...]
97
+ ✓ Task complete
98
+
99
+ Working on task 4/7: <task description>
100
+ [...implementation happening...]
101
+ ✓ Task complete
102
+ ```
103
+
104
+ **Output On Completion**
105
+
106
+ ```
107
+ ## Implementation Complete
108
+
109
+ **Change:** <change-name>
110
+ **Schema:** <schema-name>
111
+ **Progress:** 7/7 tasks complete ✓
112
+
113
+ ### Completed This Session
114
+ - [x] Task 1
115
+ - [x] Task 2
116
+ ...
117
+
118
+ All tasks complete! Ready to archive this change.
119
+ ```
120
+
121
+ **Output On Pause (Issue Encountered)**
122
+
123
+ ```
124
+ ## Implementation Paused
125
+
126
+ **Change:** <change-name>
127
+ **Schema:** <schema-name>
128
+ **Progress:** 4/7 tasks complete
129
+
130
+ ### Issue Encountered
131
+ <description of the issue>
132
+
133
+ **Options:**
134
+ 1. <option 1>
135
+ 2. <option 2>
136
+ 3. Other approach
137
+
138
+ What would you like to do?
139
+ ```
140
+
141
+ **Guardrails**
142
+ - Keep going through tasks until done or blocked
143
+ - Always read context files before starting (from the apply instructions output)
144
+ - If task is ambiguous, pause and ask before implementing
145
+ - If implementation reveals issues, pause and suggest artifact updates
146
+ - Keep code changes minimal and scoped to each task
147
+ - Update task checkbox immediately after completing each task
148
+ - Pause on errors, blockers, or unclear requirements - don't guess
149
+ - Use contextFiles from CLI output, don't assume specific file names
150
+
151
+ **Fluid Workflow Integration**
152
+
153
+ This skill supports the "actions on a change" model:
154
+
155
+ - **Can be invoked anytime**: Before all artifacts are done (if tasks exist), after partial implementation, interleaved with other actions
156
+ - **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly
.github/skills/openspec-archive-change/SKILL.md ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: openspec-archive-change
3
+ description: Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.
4
+ license: MIT
5
+ compatibility: Requires openspec CLI.
6
+ metadata:
7
+ author: openspec
8
+ version: "1.0"
9
+ generatedBy: "1.2.0"
10
+ ---
11
+
12
+ Archive a completed change in the experimental workflow.
13
+
14
+ **Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
15
+
16
+ **Steps**
17
+
18
+ 1. **If no change name provided, prompt for selection**
19
+
20
+ Run `openspec list --json` to get available changes. Use the **AskUserQuestion tool** to let the user select.
21
+
22
+ Show only active changes (not already archived).
23
+ Include the schema used for each change if available.
24
+
25
+ **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
26
+
27
+ 2. **Check artifact completion status**
28
+
29
+ Run `openspec status --change "<name>" --json` to check artifact completion.
30
+
31
+ Parse the JSON to understand:
32
+ - `schemaName`: The workflow being used
33
+ - `artifacts`: List of artifacts with their status (`done` or other)
34
+
35
+ **If any artifacts are not `done`:**
36
+ - Display warning listing incomplete artifacts
37
+ - Use **AskUserQuestion tool** to confirm user wants to proceed
38
+ - Proceed if user confirms
39
+
40
+ 3. **Check task completion status**
41
+
42
+ Read the tasks file (typically `tasks.md`) to check for incomplete tasks.
43
+
44
+ Count tasks marked with `- [ ]` (incomplete) vs `- [x]` (complete).
45
+
46
+ **If incomplete tasks found:**
47
+ - Display warning showing count of incomplete tasks
48
+ - Use **AskUserQuestion tool** to confirm user wants to proceed
49
+ - Proceed if user confirms
50
+
51
+ **If no tasks file exists:** Proceed without task-related warning.
52
+
53
+ 4. **Assess delta spec sync state**
54
+
55
+ Check for delta specs at `openspec/changes/<name>/specs/`. If none exist, proceed without sync prompt.
56
+
57
+ **If delta specs exist:**
58
+ - Compare each delta spec with its corresponding main spec at `openspec/specs/<capability>/spec.md`
59
+ - Determine what changes would be applied (adds, modifications, removals, renames)
60
+ - Show a combined summary before prompting
61
+
62
+ **Prompt options:**
63
+ - If changes needed: "Sync now (recommended)", "Archive without syncing"
64
+ - If already synced: "Archive now", "Sync anyway", "Cancel"
65
+
66
+ If user chooses sync, use Task tool (subagent_type: "general-purpose", prompt: "Use Skill tool to invoke openspec-sync-specs for change '<name>'. Delta spec analysis: <include the analyzed delta spec summary>"). Proceed to archive regardless of choice.
67
+
68
+ 5. **Perform the archive**
69
+
70
+ Create the archive directory if it doesn't exist:
71
+ ```bash
72
+ mkdir -p openspec/changes/archive
73
+ ```
74
+
75
+ Generate target name using current date: `YYYY-MM-DD-<change-name>`
76
+
77
+ **Check if target already exists:**
78
+ - If yes: Fail with error, suggest renaming existing archive or using different date
79
+ - If no: Move the change directory to archive
80
+
81
+ ```bash
82
+ mv openspec/changes/<name> openspec/changes/archive/YYYY-MM-DD-<name>
83
+ ```
84
+
85
+ 6. **Display summary**
86
+
87
+ Show archive completion summary including:
88
+ - Change name
89
+ - Schema that was used
90
+ - Archive location
91
+ - Whether specs were synced (if applicable)
92
+ - Note about any warnings (incomplete artifacts/tasks)
93
+
94
+ **Output On Success**
95
+
96
+ ```
97
+ ## Archive Complete
98
+
99
+ **Change:** <change-name>
100
+ **Schema:** <schema-name>
101
+ **Archived to:** openspec/changes/archive/YYYY-MM-DD-<name>/
102
+ **Specs:** ✓ Synced to main specs (or "No delta specs" or "Sync skipped")
103
+
104
+ All artifacts complete. All tasks complete.
105
+ ```
106
+
107
+ **Guardrails**
108
+ - Always prompt for change selection if not provided
109
+ - Use artifact graph (openspec status --json) for completion checking
110
+ - Don't block archive on warnings - just inform and confirm
111
+ - Preserve .openspec.yaml when moving to archive (it moves with the directory)
112
+ - Show clear summary of what happened
113
+ - If sync is requested, use openspec-sync-specs approach (agent-driven)
114
+ - If delta specs exist, always run the sync assessment and show the combined summary before prompting
.github/skills/openspec-bulk-archive-change/SKILL.md ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: openspec-bulk-archive-change
3
+ description: Archive multiple completed changes at once. Use when archiving several parallel changes.
4
+ license: MIT
5
+ compatibility: Requires openspec CLI.
6
+ metadata:
7
+ author: openspec
8
+ version: "1.0"
9
+ generatedBy: "1.2.0"
10
+ ---
11
+
12
+ Archive multiple completed changes in a single operation.
13
+
14
+ This skill allows you to batch-archive changes, handling spec conflicts intelligently by checking the codebase to determine what's actually implemented.
15
+
16
+ **Input**: None required (prompts for selection)
17
+
18
+ **Steps**
19
+
20
+ 1. **Get active changes**
21
+
22
+ Run `openspec list --json` to get all active changes.
23
+
24
+ If no active changes exist, inform user and stop.
25
+
26
+ 2. **Prompt for change selection**
27
+
28
+ Use **AskUserQuestion tool** with multi-select to let user choose changes:
29
+ - Show each change with its schema
30
+ - Include an option for "All changes"
31
+ - Allow any number of selections (1+ works, 2+ is the typical use case)
32
+
33
+ **IMPORTANT**: Do NOT auto-select. Always let the user choose.
34
+
35
+ 3. **Batch validation - gather status for all selected changes**
36
+
37
+ For each selected change, collect:
38
+
39
+ a. **Artifact status** - Run `openspec status --change "<name>" --json`
40
+ - Parse `schemaName` and `artifacts` list
41
+ - Note which artifacts are `done` vs other states
42
+
43
+ b. **Task completion** - Read `openspec/changes/<name>/tasks.md`
44
+ - Count `- [ ]` (incomplete) vs `- [x]` (complete)
45
+ - If no tasks file exists, note as "No tasks"
46
+
47
+ c. **Delta specs** - Check `openspec/changes/<name>/specs/` directory
48
+ - List which capability specs exist
49
+ - For each, extract requirement names (lines matching `### Requirement: <name>`)
50
+
51
+ 4. **Detect spec conflicts**
52
+
53
+ Build a map of `capability -> [changes that touch it]`:
54
+
55
+ ```
56
+ auth -> [change-a, change-b] <- CONFLICT (2+ changes)
57
+ api -> [change-c] <- OK (only 1 change)
58
+ ```
59
+
60
+ A conflict exists when 2+ selected changes have delta specs for the same capability.
61
+
62
+ 5. **Resolve conflicts agentically**
63
+
64
+ **For each conflict**, investigate the codebase:
65
+
66
+ a. **Read the delta specs** from each conflicting change to understand what each claims to add/modify
67
+
68
+ b. **Search the codebase** for implementation evidence:
69
+ - Look for code implementing requirements from each delta spec
70
+ - Check for related files, functions, or tests
71
+
72
+ c. **Determine resolution**:
73
+ - If only one change is actually implemented -> sync that one's specs
74
+ - If both implemented -> apply in chronological order (older first, newer overwrites)
75
+ - If neither implemented -> skip spec sync, warn user
76
+
77
+ d. **Record resolution** for each conflict:
78
+ - Which change's specs to apply
79
+ - In what order (if both)
80
+ - Rationale (what was found in codebase)
81
+
82
+ 6. **Show consolidated status table**
83
+
84
+ Display a table summarizing all changes:
85
+
86
+ ```
87
+ | Change | Artifacts | Tasks | Specs | Conflicts | Status |
88
+ |---------------------|-----------|-------|---------|-----------|--------|
89
+ | schema-management | Done | 5/5 | 2 delta | None | Ready |
90
+ | project-config | Done | 3/3 | 1 delta | None | Ready |
91
+ | add-oauth | Done | 4/4 | 1 delta | auth (!) | Ready* |
92
+ | add-verify-skill | 1 left | 2/5 | None | None | Warn |
93
+ ```
94
+
95
+ For conflicts, show the resolution:
96
+ ```
97
+ * Conflict resolution:
98
+ - auth spec: Will apply add-oauth then add-jwt (both implemented, chronological order)
99
+ ```
100
+
101
+ For incomplete changes, show warnings:
102
+ ```
103
+ Warnings:
104
+ - add-verify-skill: 1 incomplete artifact, 3 incomplete tasks
105
+ ```
106
+
107
+ 7. **Confirm batch operation**
108
+
109
+ Use **AskUserQuestion tool** with a single confirmation:
110
+
111
+ - "Archive N changes?" with options based on status
112
+ - Options might include:
113
+ - "Archive all N changes"
114
+ - "Archive only N ready changes (skip incomplete)"
115
+ - "Cancel"
116
+
117
+ If there are incomplete changes, make clear they'll be archived with warnings.
118
+
119
+ 8. **Execute archive for each confirmed change**
120
+
121
+ Process changes in the determined order (respecting conflict resolution):
122
+
123
+ a. **Sync specs** if delta specs exist:
124
+ - Use the openspec-sync-specs approach (agent-driven intelligent merge)
125
+ - For conflicts, apply in resolved order
126
+ - Track if sync was done
127
+
128
+ b. **Perform the archive**:
129
+ ```bash
130
+ mkdir -p openspec/changes/archive
131
+ mv openspec/changes/<name> openspec/changes/archive/YYYY-MM-DD-<name>
132
+ ```
133
+
134
+ c. **Track outcome** for each change:
135
+ - Success: archived successfully
136
+ - Failed: error during archive (record error)
137
+ - Skipped: user chose not to archive (if applicable)
138
+
139
+ 9. **Display summary**
140
+
141
+ Show final results:
142
+
143
+ ```
144
+ ## Bulk Archive Complete
145
+
146
+ Archived 3 changes:
147
+ - schema-management-cli -> archive/2026-01-19-schema-management-cli/
148
+ - project-config -> archive/2026-01-19-project-config/
149
+ - add-oauth -> archive/2026-01-19-add-oauth/
150
+
151
+ Skipped 1 change:
152
+ - add-verify-skill (user chose not to archive incomplete)
153
+
154
+ Spec sync summary:
155
+ - 4 delta specs synced to main specs
156
+ - 1 conflict resolved (auth: applied both in chronological order)
157
+ ```
158
+
159
+ If any failures:
160
+ ```
161
+ Failed 1 change:
162
+ - some-change: Archive directory already exists
163
+ ```
164
+
165
+ **Conflict Resolution Examples**
166
+
167
+ Example 1: Only one implemented
168
+ ```
169
+ Conflict: specs/auth/spec.md touched by [add-oauth, add-jwt]
170
+
171
+ Checking add-oauth:
172
+ - Delta adds "OAuth Provider Integration" requirement
173
+ - Searching codebase... found src/auth/oauth.ts implementing OAuth flow
174
+
175
+ Checking add-jwt:
176
+ - Delta adds "JWT Token Handling" requirement
177
+ - Searching codebase... no JWT implementation found
178
+
179
+ Resolution: Only add-oauth is implemented. Will sync add-oauth specs only.
180
+ ```
181
+
182
+ Example 2: Both implemented
183
+ ```
184
+ Conflict: specs/api/spec.md touched by [add-rest-api, add-graphql]
185
+
186
+ Checking add-rest-api (created 2026-01-10):
187
+ - Delta adds "REST Endpoints" requirement
188
+ - Searching codebase... found src/api/rest.ts
189
+
190
+ Checking add-graphql (created 2026-01-15):
191
+ - Delta adds "GraphQL Schema" requirement
192
+ - Searching codebase... found src/api/graphql.ts
193
+
194
+ Resolution: Both implemented. Will apply add-rest-api specs first,
195
+ then add-graphql specs (chronological order, newer takes precedence).
196
+ ```
197
+
198
+ **Output On Success**
199
+
200
+ ```
201
+ ## Bulk Archive Complete
202
+
203
+ Archived N changes:
204
+ - <change-1> -> archive/YYYY-MM-DD-<change-1>/
205
+ - <change-2> -> archive/YYYY-MM-DD-<change-2>/
206
+
207
+ Spec sync summary:
208
+ - N delta specs synced to main specs
209
+ - No conflicts (or: M conflicts resolved)
210
+ ```
211
+
212
+ **Output On Partial Success**
213
+
214
+ ```
215
+ ## Bulk Archive Complete (partial)
216
+
217
+ Archived N changes:
218
+ - <change-1> -> archive/YYYY-MM-DD-<change-1>/
219
+
220
+ Skipped M changes:
221
+ - <change-2> (user chose not to archive incomplete)
222
+
223
+ Failed K changes:
224
+ - <change-3>: Archive directory already exists
225
+ ```
226
+
227
+ **Output When No Changes**
228
+
229
+ ```
230
+ ## No Changes to Archive
231
+
232
+ No active changes found. Create a new change to get started.
233
+ ```
234
+
235
+ **Guardrails**
236
+ - Allow any number of changes (1+ is fine, 2+ is the typical use case)
237
+ - Always prompt for selection, never auto-select
238
+ - Detect spec conflicts early and resolve by checking codebase
239
+ - When both changes are implemented, apply specs in chronological order
240
+ - Skip spec sync only when implementation is missing (warn user)
241
+ - Show clear per-change status before confirming
242
+ - Use single confirmation for entire batch
243
+ - Track and report all outcomes (success/skip/fail)
244
+ - Preserve .openspec.yaml when moving to archive
245
+ - Archive directory target uses current date: YYYY-MM-DD-<name>
246
+ - If archive target exists, fail that change but continue with others
.github/skills/openspec-continue-change/SKILL.md ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: openspec-continue-change
3
+ description: Continue working on an OpenSpec change by creating the next artifact. Use when the user wants to progress their change, create the next artifact, or continue their workflow.
4
+ license: MIT
5
+ compatibility: Requires openspec CLI.
6
+ metadata:
7
+ author: openspec
8
+ version: "1.0"
9
+ generatedBy: "1.2.0"
10
+ ---
11
+
12
+ Continue working on a change by creating the next artifact.
13
+
14
+ **Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
15
+
16
+ **Steps**
17
+
18
+ 1. **If no change name provided, prompt for selection**
19
+
20
+ Run `openspec list --json` to get available changes sorted by most recently modified. Then use the **AskUserQuestion tool** to let the user select which change to work on.
21
+
22
+ Present the top 3-4 most recently modified changes as options, showing:
23
+ - Change name
24
+ - Schema (from `schema` field if present, otherwise "spec-driven")
25
+ - Status (e.g., "0/5 tasks", "complete", "no tasks")
26
+ - How recently it was modified (from `lastModified` field)
27
+
28
+ Mark the most recently modified change as "(Recommended)" since it's likely what the user wants to continue.
29
+
30
+ **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
31
+
32
+ 2. **Check current status**
33
+ ```bash
34
+ openspec status --change "<name>" --json
35
+ ```
36
+ Parse the JSON to understand current state. The response includes:
37
+ - `schemaName`: The workflow schema being used (e.g., "spec-driven")
38
+ - `artifacts`: Array of artifacts with their status ("done", "ready", "blocked")
39
+ - `isComplete`: Boolean indicating if all artifacts are complete
40
+
41
+ 3. **Act based on status**:
42
+
43
+ ---
44
+
45
+ **If all artifacts are complete (`isComplete: true`)**:
46
+ - Congratulate the user
47
+ - Show final status including the schema used
48
+ - Suggest: "All artifacts created! You can now implement this change or archive it."
49
+ - STOP
50
+
51
+ ---
52
+
53
+ **If artifacts are ready to create** (status shows artifacts with `status: "ready"`):
54
+ - Pick the FIRST artifact with `status: "ready"` from the status output
55
+ - Get its instructions:
56
+ ```bash
57
+ openspec instructions <artifact-id> --change "<name>" --json
58
+ ```
59
+ - Parse the JSON. The key fields are:
60
+ - `context`: Project background (constraints for you - do NOT include in output)
61
+ - `rules`: Artifact-specific rules (constraints for you - do NOT include in output)
62
+ - `template`: The structure to use for your output file
63
+ - `instruction`: Schema-specific guidance
64
+ - `outputPath`: Where to write the artifact
65
+ - `dependencies`: Completed artifacts to read for context
66
+ - **Create the artifact file**:
67
+ - Read any completed dependency files for context
68
+ - Use `template` as the structure - fill in its sections
69
+ - Apply `context` and `rules` as constraints when writing - but do NOT copy them into the file
70
+ - Write to the output path specified in instructions
71
+ - Show what was created and what's now unlocked
72
+ - STOP after creating ONE artifact
73
+
74
+ ---
75
+
76
+ **If no artifacts are ready (all blocked)**:
77
+ - This shouldn't happen with a valid schema
78
+ - Show status and suggest checking for issues
79
+
80
+ 4. **After creating an artifact, show progress**
81
+ ```bash
82
+ openspec status --change "<name>"
83
+ ```
84
+
85
+ **Output**
86
+
87
+ After each invocation, show:
88
+ - Which artifact was created
89
+ - Schema workflow being used
90
+ - Current progress (N/M complete)
91
+ - What artifacts are now unlocked
92
+ - Prompt: "Want to continue? Just ask me to continue or tell me what to do next."
93
+
94
+ **Artifact Creation Guidelines**
95
+
96
+ The artifact types and their purpose depend on the schema. Use the `instruction` field from the instructions output to understand what to create.
97
+
98
+ Common artifact patterns:
99
+
100
+ **spec-driven schema** (proposal → specs → design → tasks):
101
+ - **proposal.md**: Ask user about the change if not clear. Fill in Why, What Changes, Capabilities, Impact.
102
+ - The Capabilities section is critical - each capability listed will need a spec file.
103
+ - **specs/<capability>/spec.md**: Create one spec per capability listed in the proposal's Capabilities section (use the capability name, not the change name).
104
+ - **design.md**: Document technical decisions, architecture, and implementation approach.
105
+ - **tasks.md**: Break down implementation into checkboxed tasks.
106
+
107
+ For other schemas, follow the `instruction` field from the CLI output.
108
+
109
+ **Guardrails**
110
+ - Create ONE artifact per invocation
111
+ - Always read dependency artifacts before creating a new one
112
+ - Never skip artifacts or create out of order
113
+ - If context is unclear, ask the user before creating
114
+ - Verify the artifact file exists after writing before marking progress
115
+ - Use the schema's artifact sequence, don't assume specific artifact names
116
+ - **IMPORTANT**: `context` and `rules` are constraints for YOU, not content for the file
117
+ - Do NOT copy `<context>`, `<rules>`, `<project_context>` blocks into the artifact
118
+ - These guide what you write, but should never appear in the output
.github/skills/openspec-explore/SKILL.md ADDED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: openspec-explore
3
+ description: Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.
4
+ license: MIT
5
+ compatibility: Requires openspec CLI.
6
+ metadata:
7
+ author: openspec
8
+ version: "1.0"
9
+ generatedBy: "1.2.0"
10
+ ---
11
+
12
+ Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes.
13
+
14
+ **IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing.
15
+
16
+ **This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore.
17
+
18
+ ---
19
+
20
+ ## The Stance
21
+
22
+ - **Curious, not prescriptive** - Ask questions that emerge naturally, don't follow a script
23
+ - **Open threads, not interrogations** - Surface multiple interesting directions and let the user follow what resonates. Don't funnel them through a single path of questions.
24
+ - **Visual** - Use ASCII diagrams liberally when they'd help clarify thinking
25
+ - **Adaptive** - Follow interesting threads, pivot when new information emerges
26
+ - **Patient** - Don't rush to conclusions, let the shape of the problem emerge
27
+ - **Grounded** - Explore the actual codebase when relevant, don't just theorize
28
+
29
+ ---
30
+
31
+ ## What You Might Do
32
+
33
+ Depending on what the user brings, you might:
34
+
35
+ **Explore the problem space**
36
+ - Ask clarifying questions that emerge from what they said
37
+ - Challenge assumptions
38
+ - Reframe the problem
39
+ - Find analogies
40
+
41
+ **Investigate the codebase**
42
+ - Map existing architecture relevant to the discussion
43
+ - Find integration points
44
+ - Identify patterns already in use
45
+ - Surface hidden complexity
46
+
47
+ **Compare options**
48
+ - Brainstorm multiple approaches
49
+ - Build comparison tables
50
+ - Sketch tradeoffs
51
+ - Recommend a path (if asked)
52
+
53
+ **Visualize**
54
+ ```
55
+ ┌─────────────────────────────────────────┐
56
+ │ Use ASCII diagrams liberally │
57
+ ├─────────────────────────────────────────┤
58
+ │ │
59
+ │ ┌────────┐ ┌────────┐ │
60
+ │ │ State │────────▶│ State │ │
61
+ │ │ A │ │ B │ │
62
+ │ └────────┘ └────────┘ │
63
+ │ │
64
+ │ System diagrams, state machines, │
65
+ │ data flows, architecture sketches, │
66
+ │ dependency graphs, comparison tables │
67
+ │ │
68
+ └─────────────────────────────────────────┘
69
+ ```
70
+
71
+ **Surface risks and unknowns**
72
+ - Identify what could go wrong
73
+ - Find gaps in understanding
74
+ - Suggest spikes or investigations
75
+
76
+ ---
77
+
78
+ ## OpenSpec Awareness
79
+
80
+ You have full context of the OpenSpec system. Use it naturally, don't force it.
81
+
82
+ ### Check for context
83
+
84
+ At the start, quickly check what exists:
85
+ ```bash
86
+ openspec list --json
87
+ ```
88
+
89
+ This tells you:
90
+ - If there are active changes
91
+ - Their names, schemas, and status
92
+ - What the user might be working on
93
+
94
+ ### When no change exists
95
+
96
+ Think freely. When insights crystallize, you might offer:
97
+
98
+ - "This feels solid enough to start a change. Want me to create a proposal?"
99
+ - Or keep exploring - no pressure to formalize
100
+
101
+ ### When a change exists
102
+
103
+ If the user mentions a change or you detect one is relevant:
104
+
105
+ 1. **Read existing artifacts for context**
106
+ - `openspec/changes/<name>/proposal.md`
107
+ - `openspec/changes/<name>/design.md`
108
+ - `openspec/changes/<name>/tasks.md`
109
+ - etc.
110
+
111
+ 2. **Reference them naturally in conversation**
112
+ - "Your design mentions using Redis, but we just realized SQLite fits better..."
113
+ - "The proposal scopes this to premium users, but we're now thinking everyone..."
114
+
115
+ 3. **Offer to capture when decisions are made**
116
+
117
+ | Insight Type | Where to Capture |
118
+ |--------------|------------------|
119
+ | New requirement discovered | `specs/<capability>/spec.md` |
120
+ | Requirement changed | `specs/<capability>/spec.md` |
121
+ | Design decision made | `design.md` |
122
+ | Scope changed | `proposal.md` |
123
+ | New work identified | `tasks.md` |
124
+ | Assumption invalidated | Relevant artifact |
125
+
126
+ Example offers:
127
+ - "That's a design decision. Capture it in design.md?"
128
+ - "This is a new requirement. Add it to specs?"
129
+ - "This changes scope. Update the proposal?"
130
+
131
+ 4. **The user decides** - Offer and move on. Don't pressure. Don't auto-capture.
132
+
133
+ ---
134
+
135
+ ## What You Don't Have To Do
136
+
137
+ - Follow a script
138
+ - Ask the same questions every time
139
+ - Produce a specific artifact
140
+ - Reach a conclusion
141
+ - Stay on topic if a tangent is valuable
142
+ - Be brief (this is thinking time)
143
+
144
+ ---
145
+
146
+ ## Handling Different Entry Points
147
+
148
+ **User brings a vague idea:**
149
+ ```
150
+ User: I'm thinking about adding real-time collaboration
151
+
152
+ You: Real-time collab is a big space. Let me think about this...
153
+
154
+ COLLABORATION SPECTRUM
155
+ ════════════════════════════════════════════
156
+
157
+ Awareness Coordination Sync
158
+ │ │ │
159
+ ▼ ▼ ▼
160
+ ┌────────┐ ┌────────┐ ┌────────┐
161
+ │Presence│ │Cursors │ │ CRDT │
162
+ │ "3 │ │ Multi │ │Conflict│
163
+ │online" │ │ select │ │ free │
164
+ └────────┘ └────────┘ └────────┘
165
+ │ │ │
166
+ trivial moderate complex
167
+
168
+ Where's your head at?
169
+ ```
170
+
171
+ **User brings a specific problem:**
172
+ ```
173
+ User: The auth system is a mess
174
+
175
+ You: [reads codebase]
176
+
177
+ ┌─────────────────────────────────────────────┐
178
+ │ CURRENT AUTH FLOW │
179
+ └─────────────────────────────────────────────┘
180
+
181
+ ┌─────────────┼─────────────┐
182
+ ▼ ▼ ▼
183
+ ┌─────────┐ ┌─────────┐ ┌─────────┐
184
+ │ Google │ │ GitHub │ │ Email │
185
+ │ OAuth │ │ OAuth │ │ Magic │
186
+ └────┬────┘ └────┬────┘ └────┬────┘
187
+ │ │ │
188
+ └─────────────┼─────────────┘
189
+
190
+ ┌───────────┐
191
+ │ Session │
192
+ └─────┬─────┘
193
+
194
+
195
+ ┌───────────┐
196
+ │ Perms │
197
+ └───────────┘
198
+
199
+ I see three tangles. Which one's burning?
200
+ ```
201
+
202
+ **User is stuck mid-implementation:**
203
+ ```
204
+ User: /opsx:explore add-auth-system
205
+ The OAuth integration is more complex than expected
206
+
207
+ You: [reads change artifacts]
208
+
209
+ You're on task 4: "Implement OAuth flow"
210
+
211
+ Let me trace what's involved...
212
+
213
+ [draws diagram, explores options, suggests paths]
214
+
215
+ Want to update the design to reflect this?
216
+ Or add a spike task to investigate?
217
+ ```
218
+
219
+ **User wants to compare options:**
220
+ ```
221
+ User: Should we use Postgres or SQLite?
222
+
223
+ You: Generic answer is boring. What's the context?
224
+
225
+ User: A CLI tool that tracks local dev environments
226
+
227
+ You: That changes everything.
228
+
229
+ ┌─────────────────────────────────────────────────┐
230
+ │ CLI TOOL DATA STORAGE │
231
+ └─────────────────────────────────────────────────┘
232
+
233
+ Key constraints:
234
+ • No daemon running
235
+ • Must work offline
236
+ • Single user
237
+
238
+ SQLite Postgres
239
+ Deployment embedded ✓ needs server ✗
240
+ Offline yes ✓ no ✗
241
+ Single file yes ✓ no ✗
242
+
243
+ SQLite. Not even close.
244
+
245
+ Unless... is there a sync component?
246
+ ```
247
+
248
+ ---
249
+
250
+ ## Ending Discovery
251
+
252
+ There's no required ending. Discovery might:
253
+
254
+ - **Flow into a proposal**: "Ready to start? I can create a change proposal."
255
+ - **Result in artifact updates**: "Updated design.md with these decisions"
256
+ - **Just provide clarity**: User has what they need, moves on
257
+ - **Continue later**: "We can pick this up anytime"
258
+
259
+ When it feels like things are crystallizing, you might summarize:
260
+
261
+ ```
262
+ ## What We Figured Out
263
+
264
+ **The problem**: [crystallized understanding]
265
+
266
+ **The approach**: [if one emerged]
267
+
268
+ **Open questions**: [if any remain]
269
+
270
+ **Next steps** (if ready):
271
+ - Create a change proposal
272
+ - Keep exploring: just keep talking
273
+ ```
274
+
275
+ But this summary is optional. Sometimes the thinking IS the value.
276
+
277
+ ---
278
+
279
+ ## Guardrails
280
+
281
+ - **Don't implement** - Never write code or implement features. Creating OpenSpec artifacts is fine, writing application code is not.
282
+ - **Don't fake understanding** - If something is unclear, dig deeper
283
+ - **Don't rush** - Discovery is thinking time, not task time
284
+ - **Don't force structure** - Let patterns emerge naturally
285
+ - **Don't auto-capture** - Offer to save insights, don't just do it
286
+ - **Do visualize** - A good diagram is worth many paragraphs
287
+ - **Do explore the codebase** - Ground discussions in reality
288
+ - **Do question assumptions** - Including the user's and your own
.github/skills/openspec-ff-change/SKILL.md ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: openspec-ff-change
3
+ description: Fast-forward through OpenSpec artifact creation. Use when the user wants to quickly create all artifacts needed for implementation without stepping through each one individually.
4
+ license: MIT
5
+ compatibility: Requires openspec CLI.
6
+ metadata:
7
+ author: openspec
8
+ version: "1.0"
9
+ generatedBy: "1.2.0"
10
+ ---
11
+
12
+ Fast-forward through artifact creation - generate everything needed to start implementation in one go.
13
+
14
+ **Input**: The user's request should include a change name (kebab-case) OR a description of what they want to build.
15
+
16
+ **Steps**
17
+
18
+ 1. **If no clear input provided, ask what they want to build**
19
+
20
+ Use the **AskUserQuestion tool** (open-ended, no preset options) to ask:
21
+ > "What change do you want to work on? Describe what you want to build or fix."
22
+
23
+ From their description, derive a kebab-case name (e.g., "add user authentication" → `add-user-auth`).
24
+
25
+ **IMPORTANT**: Do NOT proceed without understanding what the user wants to build.
26
+
27
+ 2. **Create the change directory**
28
+ ```bash
29
+ openspec new change "<name>"
30
+ ```
31
+ This creates a scaffolded change at `openspec/changes/<name>/`.
32
+
33
+ 3. **Get the artifact build order**
34
+ ```bash
35
+ openspec status --change "<name>" --json
36
+ ```
37
+ Parse the JSON to get:
38
+ - `applyRequires`: array of artifact IDs needed before implementation (e.g., `["tasks"]`)
39
+ - `artifacts`: list of all artifacts with their status and dependencies
40
+
41
+ 4. **Create artifacts in sequence until apply-ready**
42
+
43
+ Use the **TodoWrite tool** to track progress through the artifacts.
44
+
45
+ Loop through artifacts in dependency order (artifacts with no pending dependencies first):
46
+
47
+ a. **For each artifact that is `ready` (dependencies satisfied)**:
48
+ - Get instructions:
49
+ ```bash
50
+ openspec instructions <artifact-id> --change "<name>" --json
51
+ ```
52
+ - The instructions JSON includes:
53
+ - `context`: Project background (constraints for you - do NOT include in output)
54
+ - `rules`: Artifact-specific rules (constraints for you - do NOT include in output)
55
+ - `template`: The structure to use for your output file
56
+ - `instruction`: Schema-specific guidance for this artifact type
57
+ - `outputPath`: Where to write the artifact
58
+ - `dependencies`: Completed artifacts to read for context
59
+ - Read any completed dependency files for context
60
+ - Create the artifact file using `template` as the structure
61
+ - Apply `context` and `rules` as constraints - but do NOT copy them into the file
62
+ - Show brief progress: "✓ Created <artifact-id>"
63
+
64
+ b. **Continue until all `applyRequires` artifacts are complete**
65
+ - After creating each artifact, re-run `openspec status --change "<name>" --json`
66
+ - Check if every artifact ID in `applyRequires` has `status: "done"` in the artifacts array
67
+ - Stop when all `applyRequires` artifacts are done
68
+
69
+ c. **If an artifact requires user input** (unclear context):
70
+ - Use **AskUserQuestion tool** to clarify
71
+ - Then continue with creation
72
+
73
+ 5. **Show final status**
74
+ ```bash
75
+ openspec status --change "<name>"
76
+ ```
77
+
78
+ **Output**
79
+
80
+ After completing all artifacts, summarize:
81
+ - Change name and location
82
+ - List of artifacts created with brief descriptions
83
+ - What's ready: "All artifacts created! Ready for implementation."
84
+ - Prompt: "Run `/opsx:apply` or ask me to implement to start working on the tasks."
85
+
86
+ **Artifact Creation Guidelines**
87
+
88
+ - Follow the `instruction` field from `openspec instructions` for each artifact type
89
+ - The schema defines what each artifact should contain - follow it
90
+ - Read dependency artifacts for context before creating new ones
91
+ - Use `template` as the structure for your output file - fill in its sections
92
+ - **IMPORTANT**: `context` and `rules` are constraints for YOU, not content for the file
93
+ - Do NOT copy `<context>`, `<rules>`, `<project_context>` blocks into the artifact
94
+ - These guide what you write, but should never appear in the output
95
+
96
+ **Guardrails**
97
+ - Create ALL artifacts needed for implementation (as defined by schema's `apply.requires`)
98
+ - Always read dependency artifacts before creating a new one
99
+ - If context is critically unclear, ask the user - but prefer making reasonable decisions to keep momentum
100
+ - If a change with that name already exists, suggest continuing that change instead
101
+ - Verify each artifact file exists after writing before proceeding to next
.github/skills/openspec-new-change/SKILL.md ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: openspec-new-change
3
+ description: Start a new OpenSpec change using the experimental artifact workflow. Use when the user wants to create a new feature, fix, or modification with a structured step-by-step approach.
4
+ license: MIT
5
+ compatibility: Requires openspec CLI.
6
+ metadata:
7
+ author: openspec
8
+ version: "1.0"
9
+ generatedBy: "1.2.0"
10
+ ---
11
+
12
+ Start a new change using the experimental artifact-driven approach.
13
+
14
+ **Input**: The user's request should include a change name (kebab-case) OR a description of what they want to build.
15
+
16
+ **Steps**
17
+
18
+ 1. **If no clear input provided, ask what they want to build**
19
+
20
+ Use the **AskUserQuestion tool** (open-ended, no preset options) to ask:
21
+ > "What change do you want to work on? Describe what you want to build or fix."
22
+
23
+ From their description, derive a kebab-case name (e.g., "add user authentication" → `add-user-auth`).
24
+
25
+ **IMPORTANT**: Do NOT proceed without understanding what the user wants to build.
26
+
27
+ 2. **Determine the workflow schema**
28
+
29
+ Use the default schema (omit `--schema`) unless the user explicitly requests a different workflow.
30
+
31
+ **Use a different schema only if the user mentions:**
32
+ - A specific schema name → use `--schema <name>`
33
+ - "show workflows" or "what workflows" → run `openspec schemas --json` and let them choose
34
+
35
+ **Otherwise**: Omit `--schema` to use the default.
36
+
37
+ 3. **Create the change directory**
38
+ ```bash
39
+ openspec new change "<name>"
40
+ ```
41
+ Add `--schema <name>` only if the user requested a specific workflow.
42
+ This creates a scaffolded change at `openspec/changes/<name>/` with the selected schema.
43
+
44
+ 4. **Show the artifact status**
45
+ ```bash
46
+ openspec status --change "<name>"
47
+ ```
48
+ This shows which artifacts need to be created and which are ready (dependencies satisfied).
49
+
50
+ 5. **Get instructions for the first artifact**
51
+ The first artifact depends on the schema (e.g., `proposal` for spec-driven).
52
+ Check the status output to find the first artifact with status "ready".
53
+ ```bash
54
+ openspec instructions <first-artifact-id> --change "<name>"
55
+ ```
56
+ This outputs the template and context for creating the first artifact.
57
+
58
+ 6. **STOP and wait for user direction**
59
+
60
+ **Output**
61
+
62
+ After completing the steps, summarize:
63
+ - Change name and location
64
+ - Schema/workflow being used and its artifact sequence
65
+ - Current status (0/N artifacts complete)
66
+ - The template for the first artifact
67
+ - Prompt: "Ready to create the first artifact? Just describe what this change is about and I'll draft it, or ask me to continue."
68
+
69
+ **Guardrails**
70
+ - Do NOT create any artifacts yet - just show the instructions
71
+ - Do NOT advance beyond showing the first artifact template
72
+ - If the name is invalid (not kebab-case), ask for a valid name
73
+ - If a change with that name already exists, suggest continuing that change instead
74
+ - Pass --schema if using a non-default workflow
.github/skills/openspec-onboard/SKILL.md ADDED
@@ -0,0 +1,554 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: openspec-onboard
3
+ description: Guided onboarding for OpenSpec - walk through a complete workflow cycle with narration and real codebase work.
4
+ license: MIT
5
+ compatibility: Requires openspec CLI.
6
+ metadata:
7
+ author: openspec
8
+ version: "1.0"
9
+ generatedBy: "1.2.0"
10
+ ---
11
+
12
+ 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.
13
+
14
+ ---
15
+
16
+ ## Preflight
17
+
18
+ Before starting, check if the OpenSpec CLI is installed:
19
+
20
+ ```bash
21
+ # Unix/macOS
22
+ openspec --version 2>&1 || echo "CLI_NOT_INSTALLED"
23
+ # Windows (PowerShell)
24
+ # if (Get-Command openspec -ErrorAction SilentlyContinue) { openspec --version } else { echo "CLI_NOT_INSTALLED" }
25
+ ```
26
+
27
+ **If CLI not installed:**
28
+ > OpenSpec CLI is not installed. Install it first, then come back to `/opsx:onboard`.
29
+
30
+ Stop here if not installed.
31
+
32
+ ---
33
+
34
+ ## Phase 1: Welcome
35
+
36
+ Display:
37
+
38
+ ```
39
+ ## Welcome to OpenSpec!
40
+
41
+ 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.
42
+
43
+ **What we'll do:**
44
+ 1. Pick a small, real task in your codebase
45
+ 2. Explore the problem briefly
46
+ 3. Create a change (the container for our work)
47
+ 4. Build the artifacts: proposal → specs → design → tasks
48
+ 5. Implement the tasks
49
+ 6. Archive the completed change
50
+
51
+ **Time:** ~15-20 minutes
52
+
53
+ Let's start by finding something to work on.
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Phase 2: Task Selection
59
+
60
+ ### Codebase Analysis
61
+
62
+ Scan the codebase for small improvement opportunities. Look for:
63
+
64
+ 1. **TODO/FIXME comments** - Search for `TODO`, `FIXME`, `HACK`, `XXX` in code files
65
+ 2. **Missing error handling** - `catch` blocks that swallow errors, risky operations without try-catch
66
+ 3. **Functions without tests** - Cross-reference `src/` with test directories
67
+ 4. **Type issues** - `any` types in TypeScript files (`: any`, `as any`)
68
+ 5. **Debug artifacts** - `console.log`, `console.debug`, `debugger` statements in non-debug code
69
+ 6. **Missing validation** - User input handlers without validation
70
+
71
+ Also check recent git activity:
72
+ ```bash
73
+ # Unix/macOS
74
+ git log --oneline -10 2>/dev/null || echo "No git history"
75
+ # Windows (PowerShell)
76
+ # git log --oneline -10 2>$null; if ($LASTEXITCODE -ne 0) { echo "No git history" }
77
+ ```
78
+
79
+ ### Present Suggestions
80
+
81
+ From your analysis, present 3-4 specific suggestions:
82
+
83
+ ```
84
+ ## Task Suggestions
85
+
86
+ Based on scanning your codebase, here are some good starter tasks:
87
+
88
+ **1. [Most promising task]**
89
+ Location: `src/path/to/file.ts:42`
90
+ Scope: ~1-2 files, ~20-30 lines
91
+ Why it's good: [brief reason]
92
+
93
+ **2. [Second task]**
94
+ Location: `src/another/file.ts`
95
+ Scope: ~1 file, ~15 lines
96
+ Why it's good: [brief reason]
97
+
98
+ **3. [Third task]**
99
+ Location: [location]
100
+ Scope: [estimate]
101
+ Why it's good: [brief reason]
102
+
103
+ **4. Something else?**
104
+ Tell me what you'd like to work on.
105
+
106
+ Which task interests you? (Pick a number or describe your own)
107
+ ```
108
+
109
+ **If nothing found:** Fall back to asking what the user wants to build:
110
+ > I didn't find obvious quick wins in your codebase. What's something small you've been meaning to add or fix?
111
+
112
+ ### Scope Guardrail
113
+
114
+ If the user picks or describes something too large (major feature, multi-day work):
115
+
116
+ ```
117
+ That's a valuable task, but it's probably larger than ideal for your first OpenSpec run-through.
118
+
119
+ For learning the workflow, smaller is better—it lets you see the full cycle without getting stuck in implementation details.
120
+
121
+ **Options:**
122
+ 1. **Slice it smaller** - What's the smallest useful piece of [their task]? Maybe just [specific slice]?
123
+ 2. **Pick something else** - One of the other suggestions, or a different small task?
124
+ 3. **Do it anyway** - If you really want to tackle this, we can. Just know it'll take longer.
125
+
126
+ What would you prefer?
127
+ ```
128
+
129
+ Let the user override if they insist—this is a soft guardrail.
130
+
131
+ ---
132
+
133
+ ## Phase 3: Explore Demo
134
+
135
+ Once a task is selected, briefly demonstrate explore mode:
136
+
137
+ ```
138
+ Before we create a change, let me quickly show you **explore mode**—it's how you think through problems before committing to a direction.
139
+ ```
140
+
141
+ Spend 1-2 minutes investigating the relevant code:
142
+ - Read the file(s) involved
143
+ - Draw a quick ASCII diagram if it helps
144
+ - Note any considerations
145
+
146
+ ```
147
+ ## Quick Exploration
148
+
149
+ [Your brief analysis—what you found, any considerations]
150
+
151
+ ┌─────────────────────────────────────────┐
152
+ │ [Optional: ASCII diagram if helpful] │
153
+ └─────────────────────────────────────────┘
154
+
155
+ 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.
156
+
157
+ Now let's create a change to hold our work.
158
+ ```
159
+
160
+ **PAUSE** - Wait for user acknowledgment before proceeding.
161
+
162
+ ---
163
+
164
+ ## Phase 4: Create the Change
165
+
166
+ **EXPLAIN:**
167
+ ```
168
+ ## Creating a Change
169
+
170
+ A "change" in OpenSpec is a container for all the thinking and planning around a piece of work. It lives in `openspec/changes/<name>/` and holds your artifacts—proposal, specs, design, tasks.
171
+
172
+ Let me create one for our task.
173
+ ```
174
+
175
+ **DO:** Create the change with a derived kebab-case name:
176
+ ```bash
177
+ openspec new change "<derived-name>"
178
+ ```
179
+
180
+ **SHOW:**
181
+ ```
182
+ Created: `openspec/changes/<name>/`
183
+
184
+ The folder structure:
185
+ ```
186
+ openspec/changes/<name>/
187
+ ├── proposal.md ← Why we're doing this (empty, we'll fill it)
188
+ ├── design.md ← How we'll build it (empty)
189
+ ├── specs/ ← Detailed requirements (empty)
190
+ └── tasks.md ← Implementation checklist (empty)
191
+ ```
192
+
193
+ Now let's fill in the first artifact—the proposal.
194
+ ```
195
+
196
+ ---
197
+
198
+ ## Phase 5: Proposal
199
+
200
+ **EXPLAIN:**
201
+ ```
202
+ ## The Proposal
203
+
204
+ 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.
205
+
206
+ I'll draft one based on our task.
207
+ ```
208
+
209
+ **DO:** Draft the proposal content (don't save yet):
210
+
211
+ ```
212
+ Here's a draft proposal:
213
+
214
+ ---
215
+
216
+ ## Why
217
+
218
+ [1-2 sentences explaining the problem/opportunity]
219
+
220
+ ## What Changes
221
+
222
+ [Bullet points of what will be different]
223
+
224
+ ## Capabilities
225
+
226
+ ### New Capabilities
227
+ - `<capability-name>`: [brief description]
228
+
229
+ ### Modified Capabilities
230
+ <!-- If modifying existing behavior -->
231
+
232
+ ## Impact
233
+
234
+ - `src/path/to/file.ts`: [what changes]
235
+ - [other files if applicable]
236
+
237
+ ---
238
+
239
+ Does this capture the intent? I can adjust before we save it.
240
+ ```
241
+
242
+ **PAUSE** - Wait for user approval/feedback.
243
+
244
+ After approval, save the proposal:
245
+ ```bash
246
+ openspec instructions proposal --change "<name>" --json
247
+ ```
248
+ Then write the content to `openspec/changes/<name>/proposal.md`.
249
+
250
+ ```
251
+ Proposal saved. This is your "why" document—you can always come back and refine it as understanding evolves.
252
+
253
+ Next up: specs.
254
+ ```
255
+
256
+ ---
257
+
258
+ ## Phase 6: Specs
259
+
260
+ **EXPLAIN:**
261
+ ```
262
+ ## Specs
263
+
264
+ Specs define **what** we're building in precise, testable terms. They use a requirement/scenario format that makes expected behavior crystal clear.
265
+
266
+ For a small task like this, we might only need one spec file.
267
+ ```
268
+
269
+ **DO:** Create the spec file:
270
+ ```bash
271
+ # Unix/macOS
272
+ mkdir -p openspec/changes/<name>/specs/<capability-name>
273
+ # Windows (PowerShell)
274
+ # New-Item -ItemType Directory -Force -Path "openspec/changes/<name>/specs/<capability-name>"
275
+ ```
276
+
277
+ Draft the spec content:
278
+
279
+ ```
280
+ Here's the spec:
281
+
282
+ ---
283
+
284
+ ## ADDED Requirements
285
+
286
+ ### Requirement: <Name>
287
+
288
+ <Description of what the system should do>
289
+
290
+ #### Scenario: <Scenario name>
291
+
292
+ - **WHEN** <trigger condition>
293
+ - **THEN** <expected outcome>
294
+ - **AND** <additional outcome if needed>
295
+
296
+ ---
297
+
298
+ This format—WHEN/THEN/AND—makes requirements testable. You can literally read them as test cases.
299
+ ```
300
+
301
+ Save to `openspec/changes/<name>/specs/<capability>/spec.md`.
302
+
303
+ ---
304
+
305
+ ## Phase 7: Design
306
+
307
+ **EXPLAIN:**
308
+ ```
309
+ ## Design
310
+
311
+ The design captures **how** we'll build it—technical decisions, tradeoffs, approach.
312
+
313
+ For small changes, this might be brief. That's fine—not every change needs deep design discussion.
314
+ ```
315
+
316
+ **DO:** Draft design.md:
317
+
318
+ ```
319
+ Here's the design:
320
+
321
+ ---
322
+
323
+ ## Context
324
+
325
+ [Brief context about the current state]
326
+
327
+ ## Goals / Non-Goals
328
+
329
+ **Goals:**
330
+ - [What we're trying to achieve]
331
+
332
+ **Non-Goals:**
333
+ - [What's explicitly out of scope]
334
+
335
+ ## Decisions
336
+
337
+ ### Decision 1: [Key decision]
338
+
339
+ [Explanation of approach and rationale]
340
+
341
+ ---
342
+
343
+ For a small task, this captures the key decisions without over-engineering.
344
+ ```
345
+
346
+ Save to `openspec/changes/<name>/design.md`.
347
+
348
+ ---
349
+
350
+ ## Phase 8: Tasks
351
+
352
+ **EXPLAIN:**
353
+ ```
354
+ ## Tasks
355
+
356
+ Finally, we break the work into implementation tasks—checkboxes that drive the apply phase.
357
+
358
+ These should be small, clear, and in logical order.
359
+ ```
360
+
361
+ **DO:** Generate tasks based on specs and design:
362
+
363
+ ```
364
+ Here are the implementation tasks:
365
+
366
+ ---
367
+
368
+ ## 1. [Category or file]
369
+
370
+ - [ ] 1.1 [Specific task]
371
+ - [ ] 1.2 [Specific task]
372
+
373
+ ## 2. Verify
374
+
375
+ - [ ] 2.1 [Verification step]
376
+
377
+ ---
378
+
379
+ Each checkbox becomes a unit of work in the apply phase. Ready to implement?
380
+ ```
381
+
382
+ **PAUSE** - Wait for user to confirm they're ready to implement.
383
+
384
+ Save to `openspec/changes/<name>/tasks.md`.
385
+
386
+ ---
387
+
388
+ ## Phase 9: Apply (Implementation)
389
+
390
+ **EXPLAIN:**
391
+ ```
392
+ ## Implementation
393
+
394
+ 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.
395
+ ```
396
+
397
+ **DO:** For each task:
398
+
399
+ 1. Announce: "Working on task N: [description]"
400
+ 2. Implement the change in the codebase
401
+ 3. Reference specs/design naturally: "The spec says X, so I'm doing Y"
402
+ 4. Mark complete in tasks.md: `- [ ]` → `- [x]`
403
+ 5. Brief status: "✓ Task N complete"
404
+
405
+ Keep narration light—don't over-explain every line of code.
406
+
407
+ After all tasks:
408
+
409
+ ```
410
+ ## Implementation Complete
411
+
412
+ All tasks done:
413
+ - [x] Task 1
414
+ - [x] Task 2
415
+ - [x] ...
416
+
417
+ The change is implemented! One more step—let's archive it.
418
+ ```
419
+
420
+ ---
421
+
422
+ ## Phase 10: Archive
423
+
424
+ **EXPLAIN:**
425
+ ```
426
+ ## Archiving
427
+
428
+ When a change is complete, we archive it. This moves it from `openspec/changes/` to `openspec/changes/archive/YYYY-MM-DD-<name>/`.
429
+
430
+ Archived changes become your project's decision history—you can always find them later to understand why something was built a certain way.
431
+ ```
432
+
433
+ **DO:**
434
+ ```bash
435
+ openspec archive "<name>"
436
+ ```
437
+
438
+ **SHOW:**
439
+ ```
440
+ Archived to: `openspec/changes/archive/YYYY-MM-DD-<name>/`
441
+
442
+ The change is now part of your project's history. The code is in your codebase, the decision record is preserved.
443
+ ```
444
+
445
+ ---
446
+
447
+ ## Phase 11: Recap & Next Steps
448
+
449
+ ```
450
+ ## Congratulations!
451
+
452
+ You just completed a full OpenSpec cycle:
453
+
454
+ 1. **Explore** - Thought through the problem
455
+ 2. **New** - Created a change container
456
+ 3. **Proposal** - Captured WHY
457
+ 4. **Specs** - Defined WHAT in detail
458
+ 5. **Design** - Decided HOW
459
+ 6. **Tasks** - Broke it into steps
460
+ 7. **Apply** - Implemented the work
461
+ 8. **Archive** - Preserved the record
462
+
463
+ This same rhythm works for any size change—a small fix or a major feature.
464
+
465
+ ---
466
+
467
+ ## Command Reference
468
+
469
+ **Core workflow:**
470
+
471
+ | Command | What it does |
472
+ |---------|--------------|
473
+ | `/opsx:propose` | Create a change and generate all artifacts |
474
+ | `/opsx:explore` | Think through problems before/during work |
475
+ | `/opsx:apply` | Implement tasks from a change |
476
+ | `/opsx:archive` | Archive a completed change |
477
+
478
+ **Additional commands:**
479
+
480
+ | Command | What it does |
481
+ |---------|--------------|
482
+ | `/opsx:new` | Start a new change, step through artifacts one at a time |
483
+ | `/opsx:continue` | Continue working on an existing change |
484
+ | `/opsx:ff` | Fast-forward: create all artifacts at once |
485
+ | `/opsx:verify` | Verify implementation matches artifacts |
486
+
487
+ ---
488
+
489
+ ## What's Next?
490
+
491
+ Try `/opsx:propose` on something you actually want to build. You've got the rhythm now!
492
+ ```
493
+
494
+ ---
495
+
496
+ ## Graceful Exit Handling
497
+
498
+ ### User wants to stop mid-way
499
+
500
+ If the user says they need to stop, want to pause, or seem disengaged:
501
+
502
+ ```
503
+ No problem! Your change is saved at `openspec/changes/<name>/`.
504
+
505
+ To pick up where we left off later:
506
+ - `/opsx:continue <name>` - Resume artifact creation
507
+ - `/opsx:apply <name>` - Jump to implementation (if tasks exist)
508
+
509
+ The work won't be lost. Come back whenever you're ready.
510
+ ```
511
+
512
+ Exit gracefully without pressure.
513
+
514
+ ### User just wants command reference
515
+
516
+ If the user says they just want to see the commands or skip the tutorial:
517
+
518
+ ```
519
+ ## OpenSpec Quick Reference
520
+
521
+ **Core workflow:**
522
+
523
+ | Command | What it does |
524
+ |---------|--------------|
525
+ | `/opsx:propose <name>` | Create a change and generate all artifacts |
526
+ | `/opsx:explore` | Think through problems (no code changes) |
527
+ | `/opsx:apply <name>` | Implement tasks |
528
+ | `/opsx:archive <name>` | Archive when done |
529
+
530
+ **Additional commands:**
531
+
532
+ | Command | What it does |
533
+ |---------|--------------|
534
+ | `/opsx:new <name>` | Start a new change, step by step |
535
+ | `/opsx:continue <name>` | Continue an existing change |
536
+ | `/opsx:ff <name>` | Fast-forward: all artifacts at once |
537
+ | `/opsx:verify <name>` | Verify implementation |
538
+
539
+ Try `/opsx:propose` to start your first change.
540
+ ```
541
+
542
+ Exit gracefully.
543
+
544
+ ---
545
+
546
+ ## Guardrails
547
+
548
+ - **Follow the EXPLAIN → DO → SHOW → PAUSE pattern** at key transitions (after explore, after proposal draft, after tasks, after archive)
549
+ - **Keep narration light** during implementation—teach without lecturing
550
+ - **Don't skip phases** even if the change is small—the goal is teaching the workflow
551
+ - **Pause for acknowledgment** at marked points, but don't over-pause
552
+ - **Handle exits gracefully**—never pressure the user to continue
553
+ - **Use real codebase tasks**—don't simulate or use fake examples
554
+ - **Adjust scope gently**—guide toward smaller tasks but respect user choice
.github/skills/openspec-sync-specs/SKILL.md ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: openspec-sync-specs
3
+ description: Sync delta specs from a change to main specs. Use when the user wants to update main specs with changes from a delta spec, without archiving the change.
4
+ license: MIT
5
+ compatibility: Requires openspec CLI.
6
+ metadata:
7
+ author: openspec
8
+ version: "1.0"
9
+ generatedBy: "1.2.0"
10
+ ---
11
+
12
+ Sync delta specs from a change to main specs.
13
+
14
+ This is an **agent-driven** operation - you will read delta specs and directly edit main specs to apply the changes. This allows intelligent merging (e.g., adding a scenario without copying the entire requirement).
15
+
16
+ **Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
17
+
18
+ **Steps**
19
+
20
+ 1. **If no change name provided, prompt for selection**
21
+
22
+ Run `openspec list --json` to get available changes. Use the **AskUserQuestion tool** to let the user select.
23
+
24
+ Show changes that have delta specs (under `specs/` directory).
25
+
26
+ **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
27
+
28
+ 2. **Find delta specs**
29
+
30
+ Look for delta spec files in `openspec/changes/<name>/specs/*/spec.md`.
31
+
32
+ Each delta spec file contains sections like:
33
+ - `## ADDED Requirements` - New requirements to add
34
+ - `## MODIFIED Requirements` - Changes to existing requirements
35
+ - `## REMOVED Requirements` - Requirements to remove
36
+ - `## RENAMED Requirements` - Requirements to rename (FROM:/TO: format)
37
+
38
+ If no delta specs found, inform user and stop.
39
+
40
+ 3. **For each delta spec, apply changes to main specs**
41
+
42
+ For each capability with a delta spec at `openspec/changes/<name>/specs/<capability>/spec.md`:
43
+
44
+ a. **Read the delta spec** to understand the intended changes
45
+
46
+ b. **Read the main spec** at `openspec/specs/<capability>/spec.md` (may not exist yet)
47
+
48
+ c. **Apply changes intelligently**:
49
+
50
+ **ADDED Requirements:**
51
+ - If requirement doesn't exist in main spec → add it
52
+ - If requirement already exists → update it to match (treat as implicit MODIFIED)
53
+
54
+ **MODIFIED Requirements:**
55
+ - Find the requirement in main spec
56
+ - Apply the changes - this can be:
57
+ - Adding new scenarios (don't need to copy existing ones)
58
+ - Modifying existing scenarios
59
+ - Changing the requirement description
60
+ - Preserve scenarios/content not mentioned in the delta
61
+
62
+ **REMOVED Requirements:**
63
+ - Remove the entire requirement block from main spec
64
+
65
+ **RENAMED Requirements:**
66
+ - Find the FROM requirement, rename to TO
67
+
68
+ d. **Create new main spec** if capability doesn't exist yet:
69
+ - Create `openspec/specs/<capability>/spec.md`
70
+ - Add Purpose section (can be brief, mark as TBD)
71
+ - Add Requirements section with the ADDED requirements
72
+
73
+ 4. **Show summary**
74
+
75
+ After applying all changes, summarize:
76
+ - Which capabilities were updated
77
+ - What changes were made (requirements added/modified/removed/renamed)
78
+
79
+ **Delta Spec Format Reference**
80
+
81
+ ```markdown
82
+ ## ADDED Requirements
83
+
84
+ ### Requirement: New Feature
85
+ The system SHALL do something new.
86
+
87
+ #### Scenario: Basic case
88
+ - **WHEN** user does X
89
+ - **THEN** system does Y
90
+
91
+ ## MODIFIED Requirements
92
+
93
+ ### Requirement: Existing Feature
94
+ #### Scenario: New scenario to add
95
+ - **WHEN** user does A
96
+ - **THEN** system does B
97
+
98
+ ## REMOVED Requirements
99
+
100
+ ### Requirement: Deprecated Feature
101
+
102
+ ## RENAMED Requirements
103
+
104
+ - FROM: `### Requirement: Old Name`
105
+ - TO: `### Requirement: New Name`
106
+ ```
107
+
108
+ **Key Principle: Intelligent Merging**
109
+
110
+ Unlike programmatic merging, you can apply **partial updates**:
111
+ - To add a scenario, just include that scenario under MODIFIED - don't copy existing scenarios
112
+ - The delta represents *intent*, not a wholesale replacement
113
+ - Use your judgment to merge changes sensibly
114
+
115
+ **Output On Success**
116
+
117
+ ```
118
+ ## Specs Synced: <change-name>
119
+
120
+ Updated main specs:
121
+
122
+ **<capability-1>**:
123
+ - Added requirement: "New Feature"
124
+ - Modified requirement: "Existing Feature" (added 1 scenario)
125
+
126
+ **<capability-2>**:
127
+ - Created new spec file
128
+ - Added requirement: "Another Feature"
129
+
130
+ Main specs are now updated. The change remains active - archive when implementation is complete.
131
+ ```
132
+
133
+ **Guardrails**
134
+ - Read both delta and main specs before making changes
135
+ - Preserve existing content not mentioned in delta
136
+ - If something is unclear, ask for clarification
137
+ - Show what you're changing as you go
138
+ - The operation should be idempotent - running twice should give same result
.github/skills/openspec-verify-change/SKILL.md ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: openspec-verify-change
3
+ description: Verify implementation matches change artifacts. Use when the user wants to validate that implementation is complete, correct, and coherent before archiving.
4
+ license: MIT
5
+ compatibility: Requires openspec CLI.
6
+ metadata:
7
+ author: openspec
8
+ version: "1.0"
9
+ generatedBy: "1.2.0"
10
+ ---
11
+
12
+ Verify that an implementation matches the change artifacts (specs, tasks, design).
13
+
14
+ **Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
15
+
16
+ **Steps**
17
+
18
+ 1. **If no change name provided, prompt for selection**
19
+
20
+ Run `openspec list --json` to get available changes. Use the **AskUserQuestion tool** to let the user select.
21
+
22
+ Show changes that have implementation tasks (tasks artifact exists).
23
+ Include the schema used for each change if available.
24
+ Mark changes with incomplete tasks as "(In Progress)".
25
+
26
+ **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
27
+
28
+ 2. **Check status to understand the schema**
29
+ ```bash
30
+ openspec status --change "<name>" --json
31
+ ```
32
+ Parse the JSON to understand:
33
+ - `schemaName`: The workflow being used (e.g., "spec-driven")
34
+ - Which artifacts exist for this change
35
+
36
+ 3. **Get the change directory and load artifacts**
37
+
38
+ ```bash
39
+ openspec instructions apply --change "<name>" --json
40
+ ```
41
+
42
+ This returns the change directory and context files. Read all available artifacts from `contextFiles`.
43
+
44
+ 4. **Initialize verification report structure**
45
+
46
+ Create a report structure with three dimensions:
47
+ - **Completeness**: Track tasks and spec coverage
48
+ - **Correctness**: Track requirement implementation and scenario coverage
49
+ - **Coherence**: Track design adherence and pattern consistency
50
+
51
+ Each dimension can have CRITICAL, WARNING, or SUGGESTION issues.
52
+
53
+ 5. **Verify Completeness**
54
+
55
+ **Task Completion**:
56
+ - If tasks.md exists in contextFiles, read it
57
+ - Parse checkboxes: `- [ ]` (incomplete) vs `- [x]` (complete)
58
+ - Count complete vs total tasks
59
+ - If incomplete tasks exist:
60
+ - Add CRITICAL issue for each incomplete task
61
+ - Recommendation: "Complete task: <description>" or "Mark as done if already implemented"
62
+
63
+ **Spec Coverage**:
64
+ - If delta specs exist in `openspec/changes/<name>/specs/`:
65
+ - Extract all requirements (marked with "### Requirement:")
66
+ - For each requirement:
67
+ - Search codebase for keywords related to the requirement
68
+ - Assess if implementation likely exists
69
+ - If requirements appear unimplemented:
70
+ - Add CRITICAL issue: "Requirement not found: <requirement name>"
71
+ - Recommendation: "Implement requirement X: <description>"
72
+
73
+ 6. **Verify Correctness**
74
+
75
+ **Requirement Implementation Mapping**:
76
+ - For each requirement from delta specs:
77
+ - Search codebase for implementation evidence
78
+ - If found, note file paths and line ranges
79
+ - Assess if implementation matches requirement intent
80
+ - If divergence detected:
81
+ - Add WARNING: "Implementation may diverge from spec: <details>"
82
+ - Recommendation: "Review <file>:<lines> against requirement X"
83
+
84
+ **Scenario Coverage**:
85
+ - For each scenario in delta specs (marked with "#### Scenario:"):
86
+ - Check if conditions are handled in code
87
+ - Check if tests exist covering the scenario
88
+ - If scenario appears uncovered:
89
+ - Add WARNING: "Scenario not covered: <scenario name>"
90
+ - Recommendation: "Add test or implementation for scenario: <description>"
91
+
92
+ 7. **Verify Coherence**
93
+
94
+ **Design Adherence**:
95
+ - If design.md exists in contextFiles:
96
+ - Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:")
97
+ - Verify implementation follows those decisions
98
+ - If contradiction detected:
99
+ - Add WARNING: "Design decision not followed: <decision>"
100
+ - Recommendation: "Update implementation or revise design.md to match reality"
101
+ - If no design.md: Skip design adherence check, note "No design.md to verify against"
102
+
103
+ **Code Pattern Consistency**:
104
+ - Review new code for consistency with project patterns
105
+ - Check file naming, directory structure, coding style
106
+ - If significant deviations found:
107
+ - Add SUGGESTION: "Code pattern deviation: <details>"
108
+ - Recommendation: "Consider following project pattern: <example>"
109
+
110
+ 8. **Generate Verification Report**
111
+
112
+ **Summary Scorecard**:
113
+ ```
114
+ ## Verification Report: <change-name>
115
+
116
+ ### Summary
117
+ | Dimension | Status |
118
+ |--------------|------------------|
119
+ | Completeness | X/Y tasks, N reqs|
120
+ | Correctness | M/N reqs covered |
121
+ | Coherence | Followed/Issues |
122
+ ```
123
+
124
+ **Issues by Priority**:
125
+
126
+ 1. **CRITICAL** (Must fix before archive):
127
+ - Incomplete tasks
128
+ - Missing requirement implementations
129
+ - Each with specific, actionable recommendation
130
+
131
+ 2. **WARNING** (Should fix):
132
+ - Spec/design divergences
133
+ - Missing scenario coverage
134
+ - Each with specific recommendation
135
+
136
+ 3. **SUGGESTION** (Nice to fix):
137
+ - Pattern inconsistencies
138
+ - Minor improvements
139
+ - Each with specific recommendation
140
+
141
+ **Final Assessment**:
142
+ - If CRITICAL issues: "X critical issue(s) found. Fix before archiving."
143
+ - If only warnings: "No critical issues. Y warning(s) to consider. Ready for archive (with noted improvements)."
144
+ - If all clear: "All checks passed. Ready for archive."
145
+
146
+ **Verification Heuristics**
147
+
148
+ - **Completeness**: Focus on objective checklist items (checkboxes, requirements list)
149
+ - **Correctness**: Use keyword search, file path analysis, reasonable inference - don't require perfect certainty
150
+ - **Coherence**: Look for glaring inconsistencies, don't nitpick style
151
+ - **False Positives**: When uncertain, prefer SUGGESTION over WARNING, WARNING over CRITICAL
152
+ - **Actionability**: Every issue must have a specific recommendation with file/line references where applicable
153
+
154
+ **Graceful Degradation**
155
+
156
+ - If only tasks.md exists: verify task completion only, skip spec/design checks
157
+ - If tasks + specs exist: verify completeness and correctness, skip design
158
+ - If full artifacts: verify all three dimensions
159
+ - Always note which checks were skipped and why
160
+
161
+ **Output Format**
162
+
163
+ Use clear markdown with:
164
+ - Table for summary scorecard
165
+ - Grouped lists for issues (CRITICAL/WARNING/SUGGESTION)
166
+ - Code references in format: `file.ts:123`
167
+ - Specific, actionable recommendations
168
+ - No vague suggestions like "consider reviewing"
.vscode/mcp.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "servers": {}
3
+ }
.vscode/settings.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "terminal.integrated.env.windows": {
3
+ "AZURE_DEVOPS_PAT": "9iNB6I1NnwsCtciwIZcHEeOGH9s3ESLiY5ZbhZrlQ84Jac7x5MH1JQQJ99CAACAAAAAr9WPjAAASAZDO1ZqO"
4
+ },
5
+ "chat.useClaudeSkills": true,
6
+ "chat.useAgentSkills": true
7
+ }
ChatMemo.txt ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ �ؿ��U���{���Ohuggin### ? �s�W�妸���R�\��G
2
+ - ? �s�W�������ɭ��A�O�d���Ѥ��R�\��
3
+ - ? **������r��J��**�G�����b�s��������J�h�ӪѲ��N��
4
+ - ? **������j�ѪR**�G�䴩����B�r���B�����B�Ů浥�h�ؤ��j�覡
5
+ - ? **�ֳt�d�ҫ��s**�G�x�Ѽ����B���Ѭ�ޡB����ETF�@���J
6
+ - ? �����T�Y����ܡG
7
+ - �Ѳ��N���B�Ѳ��W�١B���e����
8
+ - �W�����v(%)�B�U�^���v(%)�B�L����v(%)
9
+ - �H�߫�(%)�B���R�ɶ�
10
+ - ������~�B�z�M���A��ܡA�ثe�i�H��J�Ѳ��N���A���Ѥ��R�Ầ�^��ij�A�O�i�H�אּ�ѳ]�w��StockList.txt�A�@���ʬd�߲M�椺���Ѳ��A�ç⵲�G(��%�B�^%�B�L%�A�H��%)�A�g�JStockResult.csv�A�Х�hugging face�M�ק����A�A�i�H�ϰݧڰ��D�H��M�ݨD�C
11
+
12
+ 1.�ݭn��L��T�H�p�Ѳ��W�١B���e����B���R�ɶ�
13
+ 2.�b Web �ɭ����s�W�@�ӧ妸���R���\��
14
+ 3.�b���G������~
15
+ 4.���@���ʤ��R�A���ڦ����IJ�o�����s
16
+
17
+ �нվ�妸���R���G�A�⵲�G�ιϪ����覡��ܦb�e���W
18
+ �������R������|���� StockResult.csv �ɮסA�⵲�G�����ιϪ���ܦb�����W��
19
+ �妸���R�i�_�קאּ�Ѻ�����textfield��J�h�����e�A���N�ثe��StockList.txtŪ�J���覡�O?
20
+
21
+ ## ? �w�����\�� (app_batch.py) - �t�Ϫ���ı��
22
+
23
+ ### ? �s�W�妸���R�\��G
24
+ - ? �s�W�������ɭ��A�O�d���Ѥ��R�\��
25
+ - ? Ū�� StockList.txt �i��妸���R
26
+ - ? ��X�����T�� StockResult.csv�G
27
+ - �Ѳ��N���B�Ѳ��W�١B���e����
28
+ - �W�����v(%)�B�U�^���v(%)�B�L����v(%)
29
+ - �H�߫�(%)�B���R�ɶ�
30
+ - ���~�T���]������~�B�z�^
31
+ - ? ���IJ�o���s�u? �}�l�妸���R�v
32
+ - ? �Y�ɶi����ܩM���G�έp
33
+ - ? ���~�B�z�G�ƾڤ����B�������~�B�N�����~��
34
+
35
+ ### ? �s�W�Ϫ���ı�ƥ\��G
36
+ - ? **���v����W����**�G�U�Ѳ��W��/�U�^/�L����v���
37
+ - ? **�H�߫״��G��**�G�w���H�߫פ��G�A���j�p���̰ܳ����v
38
+ - ? **��X�����p�F��**�G�h���תѲ���������]�e6��Ѳ��^
39
+ - ? **�����������**�G����ݦh/�ݪ�/�L��Ѳ��ƶq�έp
40
+ - ? **�Y�ɤ��ʹϪ�**�G�䴩��j�B�Y��B�a����ܸԲӸ�T
41
+ - ? **�Բӵ��G����**�G����ƾڪ���A�t�C��s�X�M�w����V
42
+
43
+ ### ? ��X�榡�G
44
+ �����Y�ɹϪ� + ���ʦ����G����A�L�ݤU���ɮ�
45
+
46
+ ### ? �ϥΤ覡�G
47
+ 1. �T�O StockList.txt �s�b�]�C��@�ӪѲ��N���^
48
+ 2. �B�� app_batch.py
49
+ 3. �}���s�����i�J Web �ɭ�
50
+ 4. �I��u? �妸�Ѳ����R�v����
51
+ 5. �I���u? �}�l�妸���R�v���s
52
+ 6. **�Y�ɬd��5�ص�ı�Ƶ��G**�G
53
+ - ? ���v����W����
54
+ - ? �H�߫״��G��
55
+ - ? ��X�����p�F��
56
+ - ? �����������
57
+ - ? �Բӵ��G����]�t�C��s�X�^
58
+
59
+ ### ? �Ϫ��\�໡���G
60
+ - **���v�����**�G���[����U�Ѳ����^�L���v
61
+ - **�H�߫פ��G**�G���V�j���ܹw�����v�V���A�C��N����V
62
+ - **�p�F��**�G�h���׵����A�A�X�D���u��Ъ�
63
+ - **�������**�G���饫���h�Ť�Ҥ@�ؤF�M
64
+
65
+ ### ? ���M�����U�G
66
+ - ���Ѳ��GAI�w���ݦh
67
+ - ����Ѳ��GAI�w���ݪ�
68
+ - �Ǧ�Ѳ��GAI�w���L��
69
+ - ���j�p�G�w���j��
70
+ - �H�߫סG�w���i�a��
71
+
72
+ ## ? �̷s��s�G������r��J�\��
73
+
74
+ ### ? �s�\��S��G
75
+ - ? **���� StockList.txt �ɮר̿�**�G���A�ݭn�dzƥ~���ɮ�
76
+ - ? **����������J**�G�b�j����r�ؤ�������J�h�ӪѲ��N��
77
+ - ? **������j�ѪR**�G�۰��ѧO�h�ؤ��j�š]����B�r���B�����B�Ů�^
78
+ - ? **�ֳt�d�ҫ��s**�G
79
+ - ?? �x�Ѽ����G�x�n�q�B�E���B�p�o��B������B�x�F�q�B�p�q
80
+ - ?? ���Ѭ�ޡGAAPL�BMSFT�BGOOGL�BTSLA�BNVDA�BAMZN
81
+ - ? ����ETF�G0050�B0056�BVTI�BVOO�BQQQ�BSPY
82
+ - ? **�M�ū��s**�G�@��M�ſ�J���e���s�}�l
83
+
84
+ ### ? ��J�d�ҡG
85
+ ```
86
+ �覡1 - ������j�G
87
+ 2330.TW
88
+ 2317.TW
89
+ 1303.TW
90
+
91
+ �覡2 - �r�����j�G
92
+ 2330.TW, 2317.TW, 1303.TW
93
+
94
+ �覡3 - �V�X���j�G
95
+ 2330.TW, 2317.TW
96
+ 1303.TW; AAPL TSLA
97
+ ```
98
+
99
+ ### ? �ϥ����紣�ɡG
100
+ - ? **���[**�G�Ҧ��ާ@���b�����W����
101
+ - ? **��ֳt**�G�I���d�ҫ��s�ߧY��J�����Ѳ�
102
+ - ? **���F��**�G�䴩���N�զX�����j�Ÿ�
103
+ - ? **��͵�**�G�M������J���ܩM�d�һ���
DARK_MODE_GUIDE.md ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 深色模式使用指南
2
+
3
+ ## 概述
4
+
5
+ StockRecommender 現已支援深色模式,為用戶提供在低光環境中更舒適的使用體驗。
6
+
7
+ ## 如何使用深色模式
8
+
9
+ ### 切換主題
10
+
11
+ 1. **點擊主題切換按鈕**:在應用程式標題欄右側,您會看到一個主題切換按鈕
12
+ - 亮色模式:顯示 "🌙 深色模式" 文字
13
+ - 深色模式:顯示 "☀️ 亮色模式" 文字
14
+
15
+ 2. **鍵盤快捷方式**:按鈕支援鍵盤導航
16
+ - 使用 Tab 鍵導航至按鈕
17
+ - 按 Enter 或 Space 鍵切換主題
18
+
19
+ ### 主題偏好設定持久化
20
+
21
+ - 您選擇的主題將被自動儲存到瀏覽器 localStorage
22
+ - 下次訪問應用程式時,系統將自動應用您的選擇
23
+ - 若瀏覽器不支援 localStorage,應用程式將使用預設亮色模式
24
+
25
+ ### 系統偏好設定
26
+
27
+ - 首次訪問時,如果您的作業系統設定為深色模式(macOS、Windows 11、Linux 等),應用程式可自動偵測並應用深色模式
28
+ - 您隨時可以手動切換,覆蓋系統設定
29
+
30
+ ## 支援的功能
31
+
32
+ ### UI 元件
33
+ - ✅ Gradio 文字框、按鈕、下拉選單等所有標準元件
34
+ - ✅ 標題和說明文字
35
+ - ✅ 邊框和背景色
36
+ - ✅ 互動狀態(懸停、焦點)
37
+
38
+ ### 圖表視覺化
39
+ - ✅ Plotly 長條圖
40
+ - ✅ Plotly 散布圖
41
+ - ✅ Plotly 雷達圖
42
+ - ✅ Plotly 圓餅圖
43
+ - ✅ 所有圖表文字和網格線均支援深色模式
44
+
45
+ ## 無障礙性
46
+
47
+ - 所有主題切換功能都支援螢幕閱讀器(ARIA 標籤)
48
+ - 完全支援鍵盤導航
49
+ - 色彩對比度符合 WCAG AA 標準,確保易讀性
50
+
51
+ ## 故障排除
52
+
53
+ ### 深色模式無法切換
54
+ 1. 清除瀏覽器快取:Ctrl+Shift+Delete(Windows)或 Cmd+Shift+Delete(Mac)
55
+ 2. 關閉並重新打開瀏覽器
56
+ 3. 確保 JavaScript 已啟用
57
+
58
+ ### localStorage 不可用
59
+ - 如果瀏覽器禁用了 localStorage,應用程式會自動回退至亮色模式
60
+ - 您可在該會話內手動切換主題,但頁面刷新後將回到預設值
61
+
62
+ ### 色彩問題
63
+ - 確保您的瀏覽器是最新版本
64
+ - 嘗試禁用瀏覽器擴展程式(特別是深色模式相關的擴展)
65
+ - 清除 CSS 快取:在開發者工具中禁用快取並重新加載頁面
66
+
67
+ ## 技術細節
68
+
69
+ ### 實現方式
70
+ - **CSS 變數**:使用 CSS 自定義屬性 (Custom Properties) 定義主題顏色
71
+ - **JavaScript 管理**:ThemeManager 類別處理主題狀態和 localStorage 持久化
72
+ - **Gradio 整合**:通過動態 HTML 注入和 CSS 覆蓋實現 Gradio 元件的主題支援
73
+
74
+ ### 顏色方案
75
+
76
+ #### 亮色模式
77
+ - 背景:#ffffff(白)
78
+ - 文字:#212529(深灰)
79
+ - 主色:#1f77b4(藍)
80
+ - 強調色:#2ca02c(綠)
81
+
82
+ #### 深色模式
83
+ - 背景:#1a1a1a(深灰)
84
+ - 文字:#e8e8e8(淺灰)
85
+ - 主色:#4a9eff(亮藍)
86
+ - 強調色:#66dd88(亮綠)
87
+
88
+ ## 回饋和建議
89
+
90
+ 如果您對深色模式有任何建議或發現問題,歡迎提交 GitHub Issue 或 Pull Request。我們期待您的反饋,以持續改進使用體驗!
StockList.xlsx ADDED
Binary file (60.2 kB). View file
 
__pycache__/app.cpython-313.pyc ADDED
Binary file (86.6 kB). View file
 
app.py ADDED
The diff for this file is too large to render. See raw diff
 
app_batch.py ADDED
@@ -0,0 +1,1104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 由 Copilot 生成 - AI 股票分析師 (含批次分析功能)
2
+ import subprocess
3
+ import sys
4
+ import os
5
+ from datetime import datetime
6
+
7
+ # 環境檢測
8
+ IS_HUGGINGFACE_SPACE = "SPACE_ID" in os.environ
9
+ print(f"運行環境: {'Hugging Face Spaces' if IS_HUGGINGFACE_SPACE else '本地環境'}")
10
+
11
+ # 檢查並安裝所需套件的函數
12
+ def install_package(package_name):
13
+ try:
14
+ __import__(package_name)
15
+ except ImportError:
16
+ print(f"正在安裝 {package_name}...")
17
+ subprocess.check_call([sys.executable, "-m", "pip", "install", package_name])
18
+
19
+ # 安裝必要套件
20
+ required_packages = [
21
+ "torch>=2.0.0",
22
+ "torchvision>=0.15.0",
23
+ "torchaudio>=2.0.0",
24
+ "yfinance>=0.2.18",
25
+ "gradio>=4.0.0",
26
+ "pandas>=1.5.0",
27
+ "numpy>=1.21.0",
28
+ "matplotlib>=3.5.0",
29
+ "plotly>=5.0.0",
30
+ "beautifulsoup4>=4.11.0",
31
+ "requests>=2.28.0",
32
+ "transformers>=4.21.0",
33
+ "accelerate>=0.20.0",
34
+ "tokenizers>=0.13.0"
35
+ ]
36
+
37
+ for package in required_packages:
38
+ package_name = package.split(">=")[0].split("==")[0]
39
+ if package_name == "beautifulsoup4":
40
+ package_name = "bs4"
41
+ try:
42
+ __import__(package_name)
43
+ except ImportError:
44
+ print(f"正在安裝 {package}...")
45
+ subprocess.check_call([sys.executable, "-m", "pip", "install", package])
46
+
47
+ # 現在導入所有套件
48
+ import gradio as gr
49
+ import yfinance as yf
50
+ import pandas as pd
51
+ import numpy as np
52
+ import matplotlib.pyplot as plt
53
+ import plotly.graph_objects as go
54
+ import plotly.express as px
55
+ from datetime import datetime, timedelta
56
+ import requests
57
+ from bs4 import BeautifulSoup
58
+ from transformers import pipeline
59
+ import warnings
60
+ warnings.filterwarnings('ignore')
61
+
62
+ # 初始化 Hugging Face 模型
63
+ print("正在載入 AI 模型...")
64
+
65
+ # 嘗試載入模型,如果失敗則使用較輕量的替代方案
66
+ try:
67
+ sentiment_analyzer = pipeline("sentiment-analysis", model="ProsusAI/finbert")
68
+ print("FinBERT 情感分析模型載入成功")
69
+ except Exception as e:
70
+ print(f"FinBERT 載入失敗,嘗試替代模型: {e}")
71
+ try:
72
+ sentiment_analyzer = pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment")
73
+ print("多語言情感分析模型載入成功")
74
+ except Exception as e2:
75
+ print(f"替代模型載入失敗: {e2}")
76
+ sentiment_analyzer = None
77
+
78
+ try:
79
+ summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
80
+ print("BART 摘要模型載入成功")
81
+ except Exception as e:
82
+ print(f"BART 載入失敗,嘗試替代模型: {e}")
83
+ try:
84
+ summarizer = pipeline("summarization", model="sshleifer/distilbart-cnn-12-6")
85
+ print("DistilBART 摘要模型載入成功")
86
+ except Exception as e2:
87
+ print(f"摘要模型載入失敗: {e2}")
88
+ summarizer = None
89
+
90
+ class StockAnalyzer:
91
+ def __init__(self):
92
+ self.data = None
93
+ self.symbol = None
94
+
95
+ def fetch_stock_data(self, symbol, period="1y"):
96
+ """獲取股票歷史數據"""
97
+ try:
98
+ ticker = yf.Ticker(symbol)
99
+ self.data = ticker.history(period=period)
100
+ self.symbol = symbol
101
+ # 獲取股票資訊
102
+ info = ticker.info
103
+ stock_name = info.get('longName', info.get('shortName', symbol))
104
+ return True, f"成功獲取 {symbol} 的歷史數據", stock_name
105
+ except Exception as e:
106
+ return False, f"數據獲取失敗: {str(e)}", None
107
+
108
+ def get_stock_info(self, symbol):
109
+ """獲取股票基本資訊"""
110
+ try:
111
+ ticker = yf.Ticker(symbol)
112
+ info = ticker.info
113
+ current_price = self.data['Close'].iloc[-1] if self.data is not None else None
114
+ stock_name = info.get('longName', info.get('shortName', symbol))
115
+ return {
116
+ 'name': stock_name,
117
+ 'current_price': current_price,
118
+ 'symbol': symbol
119
+ }
120
+ except Exception as e:
121
+ return {
122
+ 'name': symbol,
123
+ 'current_price': None,
124
+ 'symbol': symbol
125
+ }
126
+
127
+ def calculate_technical_indicators(self):
128
+ """計算技術指標"""
129
+ if self.data is None:
130
+ return None
131
+
132
+ df = self.data.copy()
133
+
134
+ # 移動平均線
135
+ df['MA5'] = df['Close'].rolling(window=5).mean()
136
+ df['MA20'] = df['Close'].rolling(window=20).mean()
137
+ df['MA60'] = df['Close'].rolling(window=60).mean()
138
+
139
+ # RSI 相對強弱指標
140
+ delta = df['Close'].diff()
141
+ gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
142
+ loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
143
+ rs = gain / loss
144
+ df['RSI'] = 100 - (100 / (1 + rs))
145
+
146
+ # MACD
147
+ exp1 = df['Close'].ewm(span=12).mean()
148
+ exp2 = df['Close'].ewm(span=26).mean()
149
+ df['MACD'] = exp1 - exp2
150
+ df['MACD_signal'] = df['MACD'].ewm(span=9).mean()
151
+
152
+ # 布林通道
153
+ df['BB_middle'] = df['Close'].rolling(window=20).mean()
154
+ bb_std = df['Close'].rolling(window=20).std()
155
+ df['BB_upper'] = df['BB_middle'] + (bb_std * 2)
156
+ df['BB_lower'] = df['BB_middle'] - (bb_std * 2)
157
+
158
+ return df
159
+
160
+ def get_news_sentiment(self, symbol):
161
+ """獲取並分析新聞情感"""
162
+ try:
163
+ # 模擬新聞標題(實際應用中需要接入新聞 API)
164
+ sample_news = [
165
+ f"{symbol} 股價創新高,投資人信心大增",
166
+ f"市場關注 {symbol} 最新財報表現",
167
+ f"{symbol} 面臨供應鏈挑戰,股價承壓",
168
+ f"分析師上調 {symbol} 目標價,看好後市",
169
+ f"{symbol} 技術創新獲得市場認可"
170
+ ]
171
+
172
+ sentiments = []
173
+
174
+ # 檢查情感分析模型是否可用
175
+ if sentiment_analyzer is None:
176
+ # 如果模型不可用,返回模擬的情感分析結果
177
+ for news in sample_news:
178
+ # 簡單的關鍵詞情感分析替代方案
179
+ positive_words = ['創新高', '信心大增', '上調', '看好', '創新', '獲得認可']
180
+ negative_words = ['挑戰', '承壓', '面臨', '下滑']
181
+
182
+ score = 0.5 # 中性
183
+ sentiment = 'NEUTRAL'
184
+
185
+ for word in positive_words:
186
+ if word in news:
187
+ score = 0.8
188
+ sentiment = 'POSITIVE'
189
+ break
190
+
191
+ for word in negative_words:
192
+ if word in news:
193
+ score = 0.8
194
+ sentiment = 'NEGATIVE'
195
+ break
196
+
197
+ sentiments.append({
198
+ 'text': news,
199
+ 'sentiment': sentiment,
200
+ 'score': score
201
+ })
202
+ else:
203
+ # 使用 AI 模型進行情感分析
204
+ for news in sample_news:
205
+ result = sentiment_analyzer(news)[0]
206
+ sentiments.append({
207
+ 'text': news,
208
+ 'sentiment': result['label'],
209
+ 'score': result['score']
210
+ })
211
+
212
+ return sentiments
213
+
214
+ except Exception as e:
215
+ return [{'text': f'新聞分析暫時無法使用: {str(e)}', 'sentiment': 'NEUTRAL', 'score': 0.5}]
216
+
217
+ def analyze_sentiment_summary(self, sentiments):
218
+ """分析情感摘要"""
219
+ if not sentiments:
220
+ return "中性"
221
+
222
+ positive_count = sum(1 for s in sentiments if s['sentiment'] == 'POSITIVE')
223
+ negative_count = sum(1 for s in sentiments if s['sentiment'] == 'NEGATIVE')
224
+
225
+ if positive_count > negative_count:
226
+ return "偏樂觀"
227
+ elif negative_count > positive_count:
228
+ return "偏悲觀"
229
+ else:
230
+ return "中性"
231
+
232
+ def calculate_prediction_probabilities(self, technical_signals, sentiment, recent_data):
233
+ """計算上漲和下跌機率"""
234
+ # 計算技術面得分
235
+ bullish_signals = sum(1 for signal in technical_signals if "多頭" in signal or "機會" in signal)
236
+ bearish_signals = sum(1 for signal in technical_signals if "空頭" in signal or "警訊" in signal)
237
+ neutral_signals = len(technical_signals) - bullish_signals - bearish_signals
238
+
239
+ # 技術面得分 (-1 到 1)
240
+ total_signals = len(technical_signals)
241
+ if total_signals > 0:
242
+ tech_score = (bullish_signals - bearish_signals) / total_signals
243
+ else:
244
+ tech_score = 0
245
+
246
+ # 情感得分 (-1 到 1)
247
+ sentiment_score = 0
248
+ if sentiment == "偏樂觀":
249
+ sentiment_score = 0.6
250
+ elif sentiment == "偏悲觀":
251
+ sentiment_score = -0.6
252
+ else:
253
+ sentiment_score = 0
254
+
255
+ # 價格動量得分
256
+ price_change = ((recent_data['Close'].iloc[-1] - recent_data['Close'].iloc[-5]) / recent_data['Close'].iloc[-5]) * 100
257
+ momentum_score = np.tanh(price_change / 10) # 標準化到 -1 到 1
258
+
259
+ # RSI 得分
260
+ latest = recent_data.iloc[-1]
261
+ rsi = latest.get('RSI', 50)
262
+ if rsi > 70:
263
+ rsi_score = -0.5 # 超買,偏空
264
+ elif rsi < 30:
265
+ rsi_score = 0.5 # 超賣,偏多
266
+ else:
267
+ rsi_score = (50 - rsi) / 100 # 標準化
268
+
269
+ # MACD 得分
270
+ macd_score = 0
271
+ if 'MACD' in latest and 'MACD_signal' in latest:
272
+ if latest['MACD'] > latest['MACD_signal']:
273
+ macd_score = 0.3
274
+ else:
275
+ macd_score = -0.3
276
+
277
+ # 綜合得分計算(加權平均)
278
+ weights = {
279
+ 'tech': 0.25,
280
+ 'sentiment': 0.20,
281
+ 'momentum': 0.25,
282
+ 'rsi': 0.15,
283
+ 'macd': 0.15
284
+ }
285
+
286
+ total_score = (
287
+ tech_score * weights['tech'] +
288
+ sentiment_score * weights['sentiment'] +
289
+ momentum_score * weights['momentum'] +
290
+ rsi_score * weights['rsi'] +
291
+ macd_score * weights['macd']
292
+ )
293
+
294
+ # 將得分轉換為機率 (使用 sigmoid 函數)
295
+ def sigmoid(x):
296
+ return 1 / (1 + np.exp(-x * 3)) # 放大 3 倍讓機率更明顯
297
+
298
+ up_probability = sigmoid(total_score) * 100
299
+ down_probability = sigmoid(-total_score) * 100
300
+ sideways_probability = 100 - up_probability - down_probability
301
+
302
+ # 確保機率總和為 100%
303
+ total_prob = up_probability + down_probability + sideways_probability
304
+ up_probability = (up_probability / total_prob) * 100
305
+ down_probability = (down_probability / total_prob) * 100
306
+ sideways_probability = (sideways_probability / total_prob) * 100
307
+
308
+ return {
309
+ 'up': max(15, min(75, up_probability)), # 限制在 15%-75% 範圍內
310
+ 'down': max(15, min(75, down_probability)), # 限制在 15%-75% 範圍內
311
+ 'sideways': max(10, sideways_probability), # 至少 10%
312
+ 'confidence': abs(total_score) # 信心度
313
+ }
314
+
315
+ def generate_comprehensive_prediction(self, technical_signals, sentiment, recent_data):
316
+ """生成綜合預測報告"""
317
+ # 計算價格變化
318
+ price_change = ((recent_data['Close'].iloc[-1] - recent_data['Close'].iloc[-5]) / recent_data['Close'].iloc[-5]) * 100
319
+
320
+ # 計算預測機率
321
+ probabilities = self.calculate_prediction_probabilities(technical_signals, sentiment, recent_data)
322
+
323
+ # 確定主要預測方向
324
+ max_prob = max(probabilities['up'], probabilities['down'], probabilities['sideways'])
325
+ if probabilities['up'] == max_prob:
326
+ main_direction = "看多"
327
+ direction_emoji = "📈"
328
+ elif probabilities['down'] == max_prob:
329
+ main_direction = "看空"
330
+ direction_emoji = "📉"
331
+ else:
332
+ main_direction = "盤整"
333
+ direction_emoji = "➡️"
334
+
335
+ # 信心度描述
336
+ confidence = probabilities['confidence']
337
+ if confidence > 0.4:
338
+ confidence_desc = "高信心"
339
+ elif confidence > 0.2:
340
+ confidence_desc = "中等信心"
341
+ else:
342
+ confidence_desc = "低信心"
343
+
344
+ report = f"""
345
+ ## 📊 {self.symbol} AI 分析報告
346
+
347
+ ### 📈 技術面分析:
348
+ {chr(10).join(f"• {signal}" for signal in technical_signals)}
349
+
350
+ ### 💭 市場情感:{sentiment}
351
+
352
+ ### 📊 近期表現:
353
+ - 5日漲跌幅:{price_change:+.2f}%
354
+ - 當前價位:${recent_data['Close'].iloc[-1]:.2f}
355
+
356
+ ### 🤖 AI 預測機率(短期 1-7天):
357
+
358
+ | 方向 | 機率 | 說明 |
359
+ |------|------|------|
360
+ | 📈 **上漲** | **{probabilities['up']:.1f}%** | 股價向上突破的可能性 |
361
+ | 📉 **下跌** | **{probabilities['down']:.1f}%** | 股價向下修正的可能性 |
362
+ | ➡️ **盤整** | **{probabilities['sideways']:.1f}%** | 股價維持震盪的可能性 |
363
+
364
+ ### 🎯 主要預測方向:
365
+ {direction_emoji} **{main_direction}** ({confidence_desc} - {confidence*100:.0f}%)
366
+
367
+ ### 📋 投資建議:
368
+ """
369
+
370
+ # 根據最高機率給出建議
371
+ if probabilities['up'] > 50:
372
+ report += """
373
+ - 💡 **多頭策略**:考慮逢低加碼或持有現有部位
374
+ - 🎯 **目標設定**:關注上方阻力位,設定合理獲利目標
375
+ - 🛡️ **風險管理**:設置止損點保護資本"""
376
+ elif probabilities['down'] > 50:
377
+ report += """
378
+ - 💡 **防守策略**:考慮減碼或等待更佳進場點
379
+ - 🎯 **支撐觀察**:留意下方支撐位是否守住
380
+ - 🛡️ **風險管理**:避免追高,控制倉位大小"""
381
+ else:
382
+ report += """
383
+ - 💡 **中性策略**:保持觀望,等待明確方向訊號
384
+ - 🎯 **區間操作**:可考慮在支撐阻力區間內操作
385
+ - 🛡️ **風險管理**:小部位測試,嚴格執行停損"""
386
+
387
+ report += f"""
388
+
389
+ ### 📅 中期展望(1個月):
390
+ 基於當前技術面和市場情緒分析,建議持續關注:
391
+ - 關鍵技術位:支撐與阻力區間
392
+ - 市場情緒變化:新聞面和資金流向
393
+ - 整體大盤走勢:系統性風險評估
394
+
395
+ ⚠️ **風險提醒**:此分析基於歷史數據和 AI 模型預測,僅供參考。投資有風險,請謹慎評估並做好風險管理!
396
+
397
+ ---
398
+ *預測信心度:{confidence*100:.0f}% | 分析時間:{datetime.now().strftime('%Y-%m-%d %H:%M')}*
399
+ """
400
+
401
+ return report
402
+
403
+ def generate_prediction(self, df, news_sentiment):
404
+ """生成預測分析"""
405
+ if df is None or len(df) < 30:
406
+ return "數據不足,無法進行預測分析"
407
+
408
+ # 獲取最新數據
409
+ latest = df.iloc[-1]
410
+ recent_data = df.tail(20)
411
+
412
+ # 技術分析信號
413
+ technical_signals = []
414
+
415
+ # 價格趋势
416
+ if latest['Close'] > latest['MA20']:
417
+ technical_signals.append("價格在20日均線之上(多頭信號)")
418
+ else:
419
+ technical_signals.append("價格在20日均線之下(空頭信號)")
420
+
421
+ # RSI 分析
422
+ rsi = latest['RSI']
423
+ if rsi > 70:
424
+ technical_signals.append(f"RSI({rsi:.1f}) 超買警訊")
425
+ elif rsi < 30:
426
+ technical_signals.append(f"RSI({rsi:.1f}) 超賣機會")
427
+ else:
428
+ technical_signals.append(f"RSI({rsi:.1f}) 正常範圍")
429
+
430
+ # MACD 分析
431
+ if latest['MACD'] > latest['MACD_signal']:
432
+ technical_signals.append("MACD 呈現多頭排列")
433
+ else:
434
+ technical_signals.append("MACD 呈現空頭排列")
435
+
436
+ # 新聞情感分析
437
+ sentiment_summary = self.analyze_sentiment_summary(news_sentiment)
438
+
439
+ # 綜合預測
440
+ prediction = self.generate_comprehensive_prediction(technical_signals, sentiment_summary, recent_data)
441
+
442
+ return prediction
443
+
444
+ # 創建分析器實例
445
+ analyzer = StockAnalyzer()
446
+
447
+ def analyze_stock(symbol):
448
+ """主要分析函數"""
449
+ if not symbol.strip():
450
+ return None, "請輸入股票代碼", ""
451
+
452
+ # 獲取數據
453
+ result = analyzer.fetch_stock_data(symbol.upper())
454
+ if len(result) == 3:
455
+ success, message, stock_name = result
456
+ else:
457
+ success, message = result
458
+ stock_name = None
459
+
460
+ if not success:
461
+ return None, message, ""
462
+
463
+ # 計算技術指標
464
+ df = analyzer.calculate_technical_indicators()
465
+
466
+ # 創建價格圖表
467
+ fig = go.Figure()
468
+
469
+ # 添加K線圖
470
+ fig.add_trace(go.Candlestick(
471
+ x=df.index,
472
+ open=df['Open'],
473
+ high=df['High'],
474
+ low=df['Low'],
475
+ close=df['Close'],
476
+ name='價格'
477
+ ))
478
+
479
+ # 添加移動平均線
480
+ fig.add_trace(go.Scatter(x=df.index, y=df['MA5'], name='MA5', line=dict(color='orange')))
481
+ fig.add_trace(go.Scatter(x=df.index, y=df['MA20'], name='MA20', line=dict(color='blue')))
482
+
483
+ fig.update_layout(
484
+ title=f'{symbol} 股價走勢與技術指標',
485
+ xaxis_title='日期',
486
+ yaxis_title='價格',
487
+ height=600
488
+ )
489
+
490
+ # 獲取新聞情感
491
+ news_sentiment = analyzer.get_news_sentiment(symbol)
492
+
493
+ # 生成預測
494
+ prediction = analyzer.generate_prediction(df, news_sentiment)
495
+
496
+ return fig, "分析完成!", prediction
497
+
498
+ def create_results_table(results):
499
+ """創建結果表格"""
500
+ if not results:
501
+ return ""
502
+
503
+ # 創建表格 HTML
504
+ table_html = """
505
+ <div style="overflow-x: auto; margin: 20px 0;">
506
+ <table style="width: 100%; border-collapse: collapse; font-family: Arial, sans-serif;">
507
+ <thead>
508
+ <tr style="background-color: #f0f0f0;">
509
+ <th style="border: 1px solid #ddd; padding: 12px; text-align: left;">股票代號</th>
510
+ <th style="border: 1px solid #ddd; padding: 12px; text-align: left;">股票名稱</th>
511
+ <th style="border: 1px solid #ddd; padding: 12px; text-align: right;">當前價格</th>
512
+ <th style="border: 1px solid #ddd; padding: 12px; text-align: right;">上漲機率(%)</th>
513
+ <th style="border: 1px solid #ddd; padding: 12px; text-align: right;">下跌機率(%)</th>
514
+ <th style="border: 1px solid #ddd; padding: 12px; text-align: right;">盤整機率(%)</th>
515
+ <th style="border: 1px solid #ddd; padding: 12px; text-align: right;">信心度(%)</th>
516
+ <th style="border: 1px solid #ddd; padding: 12px; text-align: center;">預測方向</th>
517
+ <th style="border: 1px solid #ddd; padding: 12px; text-align: left;">狀態</th>
518
+ </tr>
519
+ </thead>
520
+ <tbody>
521
+ """
522
+
523
+ for result in results:
524
+ # 判斷預測方向和顏色
525
+ if result['error_message']:
526
+ direction = "❌ 錯誤"
527
+ row_color = "#fff2f2"
528
+ else:
529
+ up_prob = float(result['up_probability'])
530
+ down_prob = float(result['down_probability'])
531
+ sideways_prob = float(result['sideways_probability'])
532
+
533
+ if up_prob > down_prob and up_prob > sideways_prob:
534
+ direction = "📈 看多"
535
+ row_color = "#f0fff0" # 淡綠色
536
+ elif down_prob > up_prob and down_prob > sideways_prob:
537
+ direction = "📉 看空"
538
+ row_color = "#fff0f0" # 淡紅色
539
+ else:
540
+ direction = "➡️ 盤整"
541
+ row_color = "#f8f8f8" # 淡灰色
542
+
543
+ status = "✅ 成功" if not result['error_message'] else f"❌ {result['error_message'][:30]}..."
544
+
545
+ table_html += f"""
546
+ <tr style="background-color: {row_color};">
547
+ <td style="border: 1px solid #ddd; padding: 8px; font-weight: bold;">{result['symbol']}</td>
548
+ <td style="border: 1px solid #ddd; padding: 8px;">{result['name']}</td>
549
+ <td style="border: 1px solid #ddd; padding: 8px; text-align: right;">{result['current_price']}</td>
550
+ <td style="border: 1px solid #ddd; padding: 8px; text-align: right;">{result['up_probability']}</td>
551
+ <td style="border: 1px solid #ddd; padding: 8px; text-align: right;">{result['down_probability']}</td>
552
+ <td style="border: 1px solid #ddd; padding: 8px; text-align: right;">{result['sideways_probability']}</td>
553
+ <td style="border: 1px solid #ddd; padding: 8px; text-align: right;">{result['confidence']}</td>
554
+ <td style="border: 1px solid #ddd; padding: 8px; text-align: center;">{direction}</td>
555
+ <td style="border: 1px solid #ddd; padding: 8px;">{status}</td>
556
+ </tr>
557
+ """
558
+
559
+ table_html += """
560
+ </tbody>
561
+ </table>
562
+ </div>
563
+ """
564
+
565
+ return table_html
566
+
567
+ def create_batch_analysis_charts(results):
568
+ """創建批次分析結果圖表"""
569
+ if not results:
570
+ return None, None, None, None
571
+
572
+ # 過濾出成功分析的結果
573
+ success_results = [r for r in results if r['error_message'] == '']
574
+
575
+ if not success_results:
576
+ return None, None, None, None
577
+
578
+ # 準備數據
579
+ symbols = [r['symbol'] for r in success_results]
580
+ up_probs = [float(r['up_probability']) for r in success_results]
581
+ down_probs = [float(r['down_probability']) for r in success_results]
582
+ sideways_probs = [float(r['sideways_probability']) for r in success_results]
583
+ confidence = [float(r['confidence']) for r in success_results]
584
+
585
+ # 1. 機率比較柱狀圖
586
+ fig_bar = go.Figure()
587
+ fig_bar.add_trace(go.Bar(name='上漲機率', x=symbols, y=up_probs, marker_color='green', opacity=0.8))
588
+ fig_bar.add_trace(go.Bar(name='下跌機率', x=symbols, y=down_probs, marker_color='red', opacity=0.8))
589
+ fig_bar.add_trace(go.Bar(name='盤整機率', x=symbols, y=sideways_probs, marker_color='gray', opacity=0.8))
590
+
591
+ fig_bar.update_layout(
592
+ title='📊 股票預測機率比較',
593
+ xaxis_title='股票代號',
594
+ yaxis_title='機率 (%)',
595
+ barmode='group',
596
+ height=500,
597
+ showlegend=True,
598
+ xaxis_tickangle=-45
599
+ )
600
+
601
+ # 2. 信心度散佈圖
602
+ fig_scatter = go.Figure()
603
+
604
+ # 根據最高機率決定顏色
605
+ colors = []
606
+ for i in range(len(success_results)):
607
+ if up_probs[i] > down_probs[i] and up_probs[i] > sideways_probs[i]:
608
+ colors.append('green') # 看多
609
+ elif down_probs[i] > up_probs[i] and down_probs[i] > sideways_probs[i]:
610
+ colors.append('red') # 看空
611
+ else:
612
+ colors.append('gray') # 盤整
613
+
614
+ fig_scatter.add_trace(go.Scatter(
615
+ x=symbols,
616
+ y=confidence,
617
+ mode='markers+text',
618
+ marker=dict(
619
+ size=[max(prob) for prob in zip(up_probs, down_probs, sideways_probs)],
620
+ sizemode='diameter',
621
+ sizeref=2,
622
+ color=colors,
623
+ opacity=0.7,
624
+ line=dict(width=2, color='white')
625
+ ),
626
+ text=[f"{conf:.1f}%" for conf in confidence],
627
+ textposition="middle center",
628
+ name='信心度'
629
+ ))
630
+
631
+ fig_scatter.update_layout(
632
+ title='🎯 預測信心度分佈 (圓圈大小=最高機率)',
633
+ xaxis_title='股票代號',
634
+ yaxis_title='信心度 (%)',
635
+ height=500,
636
+ xaxis_tickangle=-45
637
+ )
638
+
639
+ # 3. 綜合評分雷達圖 (取前6支股票)
640
+ radar_data = success_results[:6] # 限制顯示數量避免過於擁擠
641
+ fig_radar = go.Figure()
642
+
643
+ categories = ['上漲機率', '信心度', '綜合評分']
644
+
645
+ for i, result in enumerate(radar_data):
646
+ # 計算綜合評分 (上漲機率 * 信心度 / 100)
647
+ composite_score = float(result['up_probability']) * float(result['confidence']) / 100
648
+
649
+ values = [
650
+ float(result['up_probability']),
651
+ float(result['confidence']),
652
+ composite_score
653
+ ]
654
+
655
+ fig_radar.add_trace(go.Scatterpolar(
656
+ r=values + [values[0]], # 閉合雷達圖
657
+ theta=categories + [categories[0]],
658
+ fill='toself',
659
+ name=result['symbol'],
660
+ opacity=0.6
661
+ ))
662
+
663
+ fig_radar.update_layout(
664
+ polar=dict(
665
+ radialaxis=dict(
666
+ visible=True,
667
+ range=[0, 100]
668
+ )
669
+ ),
670
+ title='📈 股票綜合評分雷達圖 (前6支)',
671
+ height=500,
672
+ showlegend=True
673
+ )
674
+
675
+ # 4. 機率分佈餅圖統計
676
+ # 統計各種預測傾向的數量
677
+ bullish_count = sum(1 for r in success_results if float(r['up_probability']) > max(float(r['down_probability']), float(r['sideways_probability'])))
678
+ bearish_count = sum(1 for r in success_results if float(r['down_probability']) > max(float(r['up_probability']), float(r['sideways_probability'])))
679
+ neutral_count = len(success_results) - bullish_count - bearish_count
680
+
681
+ fig_pie = go.Figure(data=[go.Pie(
682
+ labels=['看多股票', '看空股票', '盤整股票'],
683
+ values=[bullish_count, bearish_count, neutral_count],
684
+ marker_colors=['green', 'red', 'gray'],
685
+ textinfo='label+percent+value',
686
+ hovertemplate='<b>%{label}</b><br>數量: %{value}<br>比例: %{percent}<extra></extra>'
687
+ )])
688
+
689
+ fig_pie.update_layout(
690
+ title='🥧 整體市場情緒分佈',
691
+ height=400
692
+ )
693
+
694
+ return fig_bar, fig_scatter, fig_radar, fig_pie
695
+
696
+ def batch_analyze_stocks(stock_input_text):
697
+ """批次分析股票清單"""
698
+ # 檢查輸入是否為空
699
+ if not stock_input_text or not stock_input_text.strip():
700
+ return "❌ 請輸入股票代號!", "", None, None, None, None, ""
701
+
702
+ try:
703
+ # 從文字輸入框解析股票清單
704
+ # 支援多種分隔符:換行、逗號、分號、空格
705
+ import re
706
+ stock_symbols = re.split(r'[,;\s\n]+', stock_input_text.strip())
707
+ stock_symbols = [symbol.strip().upper() for symbol in stock_symbols if symbol.strip()]
708
+
709
+ if not stock_symbols:
710
+ return "❌ 未能解析出有效的股票代號!", "", None, None, None, None, ""
711
+
712
+ # 準備結果列表
713
+ results = []
714
+ progress_messages = []
715
+
716
+ progress_messages.append(f"📊 開始批次分析 {len(stock_symbols)} 支股票...")
717
+
718
+ # 分析每支股票
719
+ for i, symbol in enumerate(stock_symbols, 1):
720
+ progress_messages.append(f"\n🔍 正在分析 ({i}/{len(stock_symbols)}): {symbol}")
721
+
722
+ try:
723
+ # 獲取股票數據
724
+ result = analyzer.fetch_stock_data(symbol.upper())
725
+ if len(result) == 3:
726
+ success, message, stock_name = result
727
+ else:
728
+ success, message = result
729
+ stock_name = symbol
730
+
731
+ if not success:
732
+ # 記錄錯誤
733
+ results.append({
734
+ 'symbol': symbol,
735
+ 'name': stock_name or symbol,
736
+ 'current_price': 'N/A',
737
+ 'up_probability': 'ERROR',
738
+ 'down_probability': 'ERROR',
739
+ 'sideways_probability': 'ERROR',
740
+ 'confidence': 'ERROR',
741
+ 'analysis_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
742
+ 'error_message': message
743
+ })
744
+ progress_messages.append(f"❌ {symbol}: {message}")
745
+ continue
746
+
747
+ # 計算技術指標
748
+ df = analyzer.calculate_technical_indicators()
749
+ if df is None or len(df) < 30:
750
+ results.append({
751
+ 'symbol': symbol,
752
+ 'name': stock_name or symbol,
753
+ 'current_price': 'N/A',
754
+ 'up_probability': 'ERROR',
755
+ 'down_probability': 'ERROR',
756
+ 'sideways_probability': 'ERROR',
757
+ 'confidence': 'ERROR',
758
+ 'analysis_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
759
+ 'error_message': '數據不足,無法分析'
760
+ })
761
+ progress_messages.append(f"❌ {symbol}: 數據不足")
762
+ continue
763
+
764
+ # 獲取新聞情感
765
+ news_sentiment = analyzer.get_news_sentiment(symbol)
766
+ sentiment_summary = analyzer.analyze_sentiment_summary(news_sentiment)
767
+
768
+ # 計算預測機率
769
+ recent_data = df.tail(20)
770
+ technical_signals = []
771
+
772
+ # 簡化的技術信號計算
773
+ latest = df.iloc[-1]
774
+ if latest['Close'] > latest['MA20']:
775
+ technical_signals.append("價格在20日均線之上")
776
+ else:
777
+ technical_signals.append("價格在20日均線之下")
778
+
779
+ probabilities = analyzer.calculate_prediction_probabilities(
780
+ technical_signals, sentiment_summary, recent_data
781
+ )
782
+
783
+ # 獲取股票資訊
784
+ stock_info = analyzer.get_stock_info(symbol)
785
+
786
+ # 記錄成功結果
787
+ results.append({
788
+ 'symbol': symbol,
789
+ 'name': stock_info['name'],
790
+ 'current_price': f"{latest['Close']:.2f}" if latest['Close'] else 'N/A',
791
+ 'up_probability': f"{probabilities['up']:.1f}",
792
+ 'down_probability': f"{probabilities['down']:.1f}",
793
+ 'sideways_probability': f"{probabilities['sideways']:.1f}",
794
+ 'confidence': f"{probabilities['confidence']*100:.1f}",
795
+ 'analysis_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
796
+ 'error_message': ''
797
+ })
798
+
799
+ progress_messages.append(f"✅ {symbol}: 分析完成")
800
+
801
+ except Exception as e:
802
+ # 處理未預期的錯誤
803
+ results.append({
804
+ 'symbol': symbol,
805
+ 'name': symbol,
806
+ 'current_price': 'N/A',
807
+ 'up_probability': 'ERROR',
808
+ 'down_probability': 'ERROR',
809
+ 'sideways_probability': 'ERROR',
810
+ 'confidence': 'ERROR',
811
+ 'analysis_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
812
+ 'error_message': f'未預期錯誤: {str(e)}'
813
+ })
814
+ progress_messages.append(f"❌ {symbol}: 未預期錯誤")
815
+
816
+ # 統計結果
817
+ success_count = len([r for r in results if r['error_message'] == ''])
818
+ error_count = len(results) - success_count
819
+
820
+ summary_message = f"""
821
+ 📈 批次分析完成!
822
+
823
+ 📊 **分析統計:**
824
+ - 總計股票數:{len(stock_symbols)}
825
+ - 成功分析:{success_count}
826
+ - 分析失敗:{error_count}
827
+
828
+ � **圖表已生成:**
829
+ - 📊 機率比較柱狀圖
830
+ - 🎯 信心度散佈圖
831
+ - 📈 綜合評分雷達圖
832
+ - 🥧 市場情緒餅圖
833
+
834
+ 🎯 **請查看下方圖表進行投資決策分析!**
835
+ """
836
+
837
+ progress_log = "\n".join(progress_messages)
838
+
839
+ # 創建圖表和結果表格
840
+ chart_bar, chart_scatter, chart_radar, chart_pie = create_batch_analysis_charts(results)
841
+ results_table = create_results_table(results)
842
+
843
+ return summary_message, progress_log, chart_bar, chart_scatter, chart_radar, chart_pie, results_table
844
+
845
+ except Exception as e:
846
+ return f"❌ 批次分析過程中發生錯誤:{str(e)}", "", None, None, None, None, ""
847
+
848
+ # 創建 Gradio 界面
849
+ with gr.Blocks(title="AI 股票分析師", theme=gr.themes.Soft()) as app:
850
+ # 主題管理腳本注入
851
+ gr.HTML("""
852
+ <script src="file:///static/theme-manager.js"></script>
853
+ <link rel="stylesheet" href="file:///css/dark_mode.css">
854
+ """)
855
+
856
+ # 標題和主題切換控制項
857
+ with gr.Row():
858
+ with gr.Column(scale=1):
859
+ gr.Markdown("# 📈 AI 股票分析師")
860
+ with gr.Column(scale=0, min_width=120):
861
+ theme_toggle_btn = gr.Button(
862
+ "🌙 深色模式",
863
+ elem_classes=["theme-toggle-btn"],
864
+ size="sm"
865
+ )
866
+
867
+ gr.Markdown(
868
+ """
869
+ ### 🤖 使用 Hugging Face 模型進行智能股票分析
870
+
871
+ **✨ 核心功能:**
872
+ - 📊 **完整技術指標**:MA、RSI、MACD、布林通道分析
873
+ - 🧠 **AI 情感分析**:使用 FinBERT 模型分析市場情緒
874
+ - 🎯 **機率預測**:提供上漲/下跌/盤整機率百分比
875
+ - 📈 **智能建議**:根據機率給出個性化投資策略
876
+ - 🖼️ **互動圖表**:動態視覺化技術指標走勢
877
+ - 📁 **批次分析**:一次分析多支股票並匯出CSV報告
878
+
879
+ **🚀 使用方法:** 單支分析輸入股票代碼,批次分析直接在文字框中輸入多個股票代號!
880
+ """
881
+ )
882
+
883
+ # 建立分頁
884
+ with gr.Tabs():
885
+ with gr.TabItem("🎯 單支股票分析"):
886
+ with gr.Row():
887
+ with gr.Column(scale=1):
888
+ stock_input = gr.Textbox(
889
+ label="股票代碼",
890
+ placeholder="例如:AAPL, TSLA, 2330.TW",
891
+ value="2330.TW"
892
+ )
893
+ analyze_btn = gr.Button("開始分析", variant="primary", size="lg")
894
+
895
+ status_output = gr.Textbox(
896
+ label="分析狀態",
897
+ lines=2,
898
+ interactive=False
899
+ )
900
+
901
+ with gr.Column(scale=2):
902
+ chart_output = gr.Plot(label="股價走勢圖")
903
+
904
+ prediction_output = gr.Markdown(label="AI 分析報告")
905
+
906
+ # 事件綁定
907
+ analyze_btn.click(
908
+ fn=analyze_stock,
909
+ inputs=[stock_input],
910
+ outputs=[chart_output, status_output, prediction_output]
911
+ )
912
+
913
+ # 範例按鈕
914
+ gr.Examples(
915
+ examples=[
916
+ ["AAPL"],
917
+ ["TSLA"],
918
+ ["2330.TW"],
919
+ ["MSFT"],
920
+ ["GOOGL"]
921
+ ],
922
+ inputs=[stock_input]
923
+ )
924
+
925
+ with gr.TabItem("📊 批次股票分析"):
926
+ gr.Markdown(
927
+ """
928
+ ### 📁 批次分析功能
929
+
930
+ **📋 使用方式:**
931
+ 1. 在下方輸入框中輸入多個股票代號
932
+ 2. 支援多種分隔方式:換行、逗號、分號、空格
933
+ 3. 點擊「開始批次分析」按鈕
934
+ 4. 查看即時互動圖表分析結果
935
+
936
+ **📈 輸出內容:**
937
+ - 📊 機率比較柱狀圖:直觀對比各股票預測機率
938
+ - 🎯 信心度散佈圖:顯示預測可靠性分佈
939
+ - 📈 綜合評分雷達圖:多維度股票評分比較
940
+ - 🥧 市場情緒餅圖:整體多空情緒統計
941
+ - 📋 詳細結果表格:完整數據一覽
942
+ """
943
+ )
944
+
945
+ # 股票代號輸入區
946
+ with gr.Row():
947
+ with gr.Column(scale=3):
948
+ stock_input_batch = gr.Textbox(
949
+ label="📝 股票代號清單",
950
+ placeholder="""請輸入多個股票代號,支援多種分隔方式:
951
+
952
+ • 換行分隔:
953
+ 2330.TW
954
+ 2317.TW
955
+ 1303.TW
956
+
957
+ • 逗號分隔:2330.TW, 2317.TW, 1303.TW
958
+
959
+ • 空格分隔:2330.TW 2317.TW 1303.TW
960
+
961
+ • 混合分隔:2330.TW, 2317.TW
962
+ 1303.TW; AAPL TSLA""",
963
+ lines=8,
964
+ value="2330.TW\n2317.TW\n1303.TW\n0050.TW"
965
+ )
966
+ with gr.Column(scale=1):
967
+ batch_analyze_btn = gr.Button(
968
+ "🚀 開始批次分析",
969
+ variant="primary",
970
+ size="lg"
971
+ )
972
+
973
+ # 快速範例按鈕
974
+ gr.Markdown("**🚀 快速範例:**")
975
+
976
+ example_tw_btn = gr.Button("🇹🇼 台股熱門", size="sm")
977
+ example_us_btn = gr.Button("🇺🇸 美股科技", size="sm")
978
+ example_etf_btn = gr.Button("📈 熱門ETF", size="sm")
979
+ clear_btn = gr.Button("🗑️ 清空", size="sm")
980
+
981
+ gr.Markdown(
982
+ """
983
+ **💡 支援格式:**
984
+ - 換行分隔
985
+ - 逗號分隔
986
+ - 空格/分號分隔
987
+ - 混合分隔
988
+ """
989
+ )
990
+
991
+ with gr.Row():
992
+ with gr.Column(scale=1):
993
+ batch_summary = gr.Markdown(label="📊 分析摘要")
994
+ with gr.Column(scale=1):
995
+ batch_progress = gr.Textbox(
996
+ label="📋 分析進度",
997
+ lines=10,
998
+ interactive=False,
999
+ max_lines=15
1000
+ )
1001
+
1002
+ # 圖表顯示區域
1003
+ gr.Markdown("## 📈 視覺化分析結果")
1004
+
1005
+ with gr.Row():
1006
+ with gr.Column(scale=1):
1007
+ chart_probability = gr.Plot(label="📊 股票預測機率比較")
1008
+ with gr.Column(scale=1):
1009
+ chart_confidence = gr.Plot(label="🎯 預測信心度分佈")
1010
+
1011
+ with gr.Row():
1012
+ with gr.Column(scale=1):
1013
+ chart_radar = gr.Plot(label="📈 綜合評分雷達圖")
1014
+ with gr.Column(scale=1):
1015
+ chart_sentiment = gr.Plot(label="🥧 整體市場情緒分佈")
1016
+
1017
+ # 詳細結果表格
1018
+ gr.Markdown("## 📋 詳細分析結果")
1019
+ results_table = gr.HTML(label="分析結果表格")
1020
+
1021
+ # 快速範例按鈕事件綁定
1022
+ example_tw_btn.click(
1023
+ lambda: "2330.TW\n2317.TW\n2454.TW\n2882.TW\n6505.TW\n2303.TW",
1024
+ outputs=[stock_input_batch]
1025
+ )
1026
+
1027
+ example_us_btn.click(
1028
+ lambda: "AAPL\nMSFT\nGOOGL\nTSLA\nNVDA\nAMZN",
1029
+ outputs=[stock_input_batch]
1030
+ )
1031
+
1032
+ example_etf_btn.click(
1033
+ lambda: "0050.TW\n0056.TW\nVTI\nVOO\nQQQ\nSPY",
1034
+ outputs=[stock_input_batch]
1035
+ )
1036
+
1037
+ clear_btn.click(
1038
+ lambda: "",
1039
+ outputs=[stock_input_batch]
1040
+ )
1041
+
1042
+ # 批次分析事件綁定
1043
+ batch_analyze_btn.click(
1044
+ fn=batch_analyze_stocks,
1045
+ inputs=[stock_input_batch],
1046
+ outputs=[
1047
+ batch_summary,
1048
+ batch_progress,
1049
+ chart_probability,
1050
+ chart_confidence,
1051
+ chart_radar,
1052
+ chart_sentiment,
1053
+ results_table
1054
+ ]
1055
+ )
1056
+
1057
+ # 啟動應用
1058
+ if __name__ == "__main__":
1059
+ print("正在啟動 AI 股票分析師...")
1060
+
1061
+ # 簡化的啟動邏輯
1062
+ try:
1063
+ if IS_HUGGINGFACE_SPACE:
1064
+ # Hugging Face Spaces 環境 - 使用預設配置
1065
+ print("在 Hugging Face Spaces 中啟動...")
1066
+ app.launch()
1067
+ else:
1068
+ # 本地環境 - 嘗試多個端口
1069
+ print("在本地環境中啟動...")
1070
+ ports_to_try = [7860, 7861, 7862, 7863, 7864, 7865]
1071
+
1072
+ launched = False
1073
+ for port in ports_to_try:
1074
+ try:
1075
+ print(f"嘗試端口 {port}...")
1076
+ app.launch(
1077
+ share=True,
1078
+ server_name="0.0.0.0",
1079
+ server_port=port,
1080
+ show_error=True,
1081
+ quiet=False
1082
+ )
1083
+ launched = True
1084
+ break
1085
+ except OSError as e:
1086
+ if "port" in str(e).lower():
1087
+ print(f"端口 {port} 不可用,嘗試下一個...")
1088
+ continue
1089
+ else:
1090
+ raise e
1091
+
1092
+ if not launched:
1093
+ print("所有預設端口都被佔用,使用隨機端口...")
1094
+ app.launch(
1095
+ share=True,
1096
+ server_name="0.0.0.0",
1097
+ server_port=0, # 0 表示自動分配端口
1098
+ show_error=True
1099
+ )
1100
+
1101
+ except Exception as e:
1102
+ print(f"啟動失敗: {e}")
1103
+ print("請檢查端口使用情況或嘗試重新啟動")
1104
+ raise e
css/dark_mode.css ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* 深色模式樣式表 - CSS 變數定義和主題支援 */
2
+
3
+ :root {
4
+ /* 亮色主題變數(預設) */
5
+ --primary-color: #1f77b4;
6
+ --secondary-color: #ff7f0e;
7
+ --accent-color: #2ca02c;
8
+ --bg-color: #ffffff;
9
+ --surface-color: #f8f9fa;
10
+ --text-color: #212529;
11
+ --text-secondary-color: #6c757d;
12
+ --border-color: #dee2e6;
13
+ --hover-color: #e9ecef;
14
+ --success-color: #28a745;
15
+ --warning-color: #ffc107;
16
+ --error-color: #dc3545;
17
+
18
+ /* 過渡設定 */
19
+ --transition-duration: 0.3s;
20
+ }
21
+
22
+ /* 深色主題變數 */
23
+ [data-theme="dark"] {
24
+ --primary-color: #4a9eff;
25
+ --secondary-color: #ffb366;
26
+ --accent-color: #66dd88;
27
+ --bg-color: #1a1a1a;
28
+ --surface-color: #2d2d2d;
29
+ --text-color: #e8e8e8;
30
+ --text-secondary-color: #a0a0a0;
31
+ --border-color: #404040;
32
+ --hover-color: #383838;
33
+ --success-color: #4ade80;
34
+ --warning-color: #facc15;
35
+ --error-color: #ef4444;
36
+ }
37
+
38
+ /* 基礎樣式應用 */
39
+ body {
40
+ background-color: var(--bg-color);
41
+ color: var(--text-color);
42
+ transition: background-color var(--transition-duration), color var(--transition-duration);
43
+ }
44
+
45
+ /* 容器和卡片 */
46
+ .container,
47
+ .card,
48
+ .panel {
49
+ background-color: var(--surface-color);
50
+ border-color: var(--border-color);
51
+ color: var(--text-color);
52
+ }
53
+
54
+ /* 按鈕樣式 */
55
+ button,
56
+ .btn {
57
+ background-color: var(--primary-color);
58
+ color: var(--bg-color);
59
+ border: none;
60
+ border-radius: 4px;
61
+ padding: 8px 16px;
62
+ cursor: pointer;
63
+ transition: background-color var(--transition-duration),
64
+ transform var(--transition-duration);
65
+ }
66
+
67
+ button:hover,
68
+ .btn:hover {
69
+ background-color: var(--accent-color);
70
+ transform: translateY(-2px);
71
+ }
72
+
73
+ button:focus,
74
+ .btn:focus {
75
+ outline: 2px solid var(--accent-color);
76
+ outline-offset: 2px;
77
+ }
78
+
79
+ /* 主題切換按鈕特定樣式 */
80
+ .theme-toggle-btn {
81
+ background-color: var(--surface-color);
82
+ color: var(--text-color);
83
+ border: 1px solid var(--border-color);
84
+ padding: 8px 12px;
85
+ border-radius: 4px;
86
+ cursor: pointer;
87
+ font-size: 14px;
88
+ transition: all var(--transition-duration);
89
+ }
90
+
91
+ .theme-toggle-btn:hover {
92
+ background-color: var(--hover-color);
93
+ border-color: var(--accent-color);
94
+ }
95
+
96
+ .theme-toggle-btn:focus {
97
+ outline: 2px solid var(--accent-color);
98
+ outline-offset: 2px;
99
+ }
100
+
101
+ /* 輸入欄位樣式 */
102
+ input,
103
+ textarea,
104
+ select {
105
+ background-color: var(--surface-color);
106
+ color: var(--text-color);
107
+ border: 1px solid var(--border-color);
108
+ padding: 8px 12px;
109
+ border-radius: 4px;
110
+ transition: border-color var(--transition-duration);
111
+ }
112
+
113
+ input:focus,
114
+ textarea:focus,
115
+ select:focus {
116
+ outline: none;
117
+ border-color: var(--accent-color);
118
+ box-shadow: 0 0 4px var(--accent-color);
119
+ }
120
+
121
+ /* 標籤和文字 */
122
+ label {
123
+ color: var(--text-color);
124
+ }
125
+
126
+ a {
127
+ color: var(--primary-color);
128
+ text-decoration: none;
129
+ }
130
+
131
+ a:hover {
132
+ color: var(--accent-color);
133
+ text-decoration: underline;
134
+ }
135
+
136
+ /* 表格樣式 */
137
+ table {
138
+ background-color: var(--surface-color);
139
+ border-collapse: collapse;
140
+ }
141
+
142
+ th {
143
+ background-color: var(--hover-color);
144
+ color: var(--text-color);
145
+ border-bottom: 2px solid var(--border-color);
146
+ }
147
+
148
+ td {
149
+ border-bottom: 1px solid var(--border-color);
150
+ padding: 12px;
151
+ color: var(--text-color);
152
+ }
153
+
154
+ tr:hover {
155
+ background-color: var(--hover-color);
156
+ }
157
+
158
+ /* 狀態顏色 */
159
+ .success {
160
+ color: var(--success-color);
161
+ }
162
+
163
+ .warning {
164
+ color: var(--warning-color);
165
+ }
166
+
167
+ .error {
168
+ color: var(--error-color);
169
+ }
170
+
171
+ /* Gradio 特定樣式 */
172
+ .gradio-container {
173
+ background-color: var(--bg-color) !important;
174
+ }
175
+
176
+ .gradio-textbox,
177
+ .gradio-number,
178
+ .gradio-slider {
179
+ background-color: var(--surface-color) !important;
180
+ color: var(--text-color) !important;
181
+ border-color: var(--border-color) !important;
182
+ }
183
+
184
+ .gradio-button {
185
+ background-color: var(--primary-color) !important;
186
+ color: var(--bg-color) !important;
187
+ border: none !important;
188
+ }
189
+
190
+ .gradio-button:hover {
191
+ background-color: var(--accent-color) !important;
192
+ }
193
+
194
+ /* 禁用狀態 */
195
+ button:disabled,
196
+ input:disabled,
197
+ select:disabled {
198
+ opacity: 0.5;
199
+ cursor: not-allowed;
200
+ }
201
+
202
+ /* 無障礙 - 焦點可視化 */
203
+ :focus-visible {
204
+ outline: 2px solid var(--accent-color);
205
+ outline-offset: 2px;
206
+ }
207
+
208
+ /* 平滑過渡 */
209
+ * {
210
+ transition: background-color var(--transition-duration),
211
+ color var(--transition-duration),
212
+ border-color var(--transition-duration);
213
+ }
214
+
215
+ /* 尊重系統深色模式偏好 */
216
+ @media (prefers-color-scheme: dark) {
217
+ :root:not([data-theme="light"]) {
218
+ --primary-color: #4a9eff;
219
+ --secondary-color: #ffb366;
220
+ --accent-color: #66dd88;
221
+ --bg-color: #1a1a1a;
222
+ --surface-color: #2d2d2d;
223
+ --text-color: #e8e8e8;
224
+ --text-secondary-color: #a0a0a0;
225
+ --border-color: #404040;
226
+ --hover-color: #383838;
227
+ --success-color: #4ade80;
228
+ --warning-color: #facc15;
229
+ --error-color: #ef4444;
230
+ }
231
+ }
docs/specify/plan/專案名稱/SDS.md ADDED
File without changes
docs/specify/plan/專案名稱/SRS.md ADDED
File without changes
docs/specify/plan/專案名稱/spec.md ADDED
File without changes
docs/specify/plan/專案名稱/tasks.md ADDED
@@ -0,0 +1 @@
 
 
1
+ ��Agent�ݪ�
docs/specify/plan/放AI產生的plan文件 ADDED
File without changes
docs/specify/templates/放AI參考的文件格式 ADDED
File without changes
openspec/changes/archive/2026-03-10-add-dark-mode/.openspec.yaml ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ schema: spec-driven
2
+ created: 2026-03-10
openspec/changes/archive/2026-03-10-add-dark-mode/design.md ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Context
2
+
3
+ StockRecommender 是一個基於 Gradio 的股票分析應用程式,目前僅支援亮色模式。應用程式通過 `app_batch.py` 和 `app.py` 提供用戶介面,使用 Plotly 進行互動式圖表展示。用戶在長時間交易時段(尤其是清晨或晚間)會面臨眼睛疲勞問題。本設計旨在引入深色模式支援,同時保持與現有亮色模式的向後相容性。
4
+
5
+ ## Goals / Non-Goals
6
+
7
+ **Goals:**
8
+ - 在 Gradio UI 中提供一個直觀的主題切換控制項
9
+ - 儲存用戶主題選擇,確保跨會話的一致體驗
10
+ - 為深色模式定義完整的色彩方案,包含 Gradio 元件和 Plotly 圖表
11
+ - 確保深色模式下的色彩對比度符合 WCAG 標準
12
+ - 支援系統偏好設定自動偵測(可選功能)
13
+ - 確保在 Hugging Face Spaces 和本地部署中均可正常運作
14
+
15
+ **Non-Goals:**
16
+ - 不支援客製化主題生成或用戶自定義顏色方案
17
+ - 不涉及後端邏輯變更或資料模型修改
18
+ - 不包括其他 UI 框架的支援(僅限 Gradio)
19
+
20
+ ## Decisions
21
+
22
+ ### 決策 1:主題儲存方式
23
+ **選擇**:優先使用瀏覽器 localStorage,伺服器端預設值作為後備方案
24
+
25
+ **理由**:localStorage 提供即時、無伺服器端依賴的持久化方案,適合 Hugging Face Spaces 的無狀態環境。伺服器端預設值用於首次訪問或 localStorage 不可用時。
26
+
27
+ **考慮的替代方案**:
28
+ - Cookie:相比 localStorage 容量限制較多,不如優先選擇
29
+ - 伺服器端會話儲存:增加伺服器複雜度,不適合無狀態部署
30
+
31
+ ### 決策 2:色彩方案實現方式
32
+ **選擇**:使用 CSS 變數 + Gradio 原生主題系統
33
+
34
+ **理由**:Gradio 3.x+ 原生支援主題切換,避免額外依賴。CSS 變數提供集中式配置,易於維護和調整。
35
+
36
+ **考慮的替代方案**:
37
+ - 動態 CSS 生成:複雜度高,維護困難
38
+ - 預定義的 CSS 類別切換:無法利用 Gradio 的主題系統
39
+
40
+ ### 決策 3:Plotly 圖表主題適配
41
+ **選擇**:根據用戶選定的主題動態更新 Plotly 配置
42
+
43
+ **理由**:Plotly 支援主題配置參數,在圖表建立時應用適當的範本和配色。這樣無需修改已有的圖表生成邏輯。
44
+
45
+ **考慮的替代方案**:
46
+ - 預先定義亮/暗兩種圖表變體:冗餘且不易維護
47
+ - JavaScript 客戶端注入:增加複雜度
48
+
49
+ ### 決策 4:主題控制項位置
50
+ **選擇**:在應用程式標題欄右側放置主題切換按鈕
51
+
52
+ **理由**:標題欄是用戶首先注意到的區域,右側位置符合常見的 UI 慣例。
53
+
54
+ ## Risks / Trade-offs
55
+
56
+ **[風險] Plotly 圖表渲染延遲**
57
+ → **風險降低措施**:在建立圖表時預先計算主題配置,避免即時轉換。
58
+
59
+ **[風險] 某些用戶瀏覽器不支援 localStorage**
60
+ → **風險降低措施**:提供伺服器端預設值和優雅降級策略,默認使用亮色模式。
61
+
62
+ **[風險] 深色模式色彩對比度不足**
63
+ → **風險降低措施**:使用經過驗證的色彩方案(例如參考深色模式設計指南),進行 WCAG 對比度檢查。
64
+
65
+ **[風險] Gradio 主題系統的跨版本相容性**
66
+ → **風險降低措施**:在 requirements.txt 中固定 Gradio 版本,確保主題系統穩定。
67
+
68
+ **[取捨] localStorage 儲存空間有限**
69
+ → 深色模式配置僅需極小的儲存空間(<1KB),此取捨可接受。
70
+
71
+ ## Migration Plan
72
+
73
+ ### 部署步驟
74
+ 1. **第 1 階段**:新增主題配置文件(`theme_config.py`)和 CSS 變數定義
75
+ 2. **第 2 階段**:修改 `app_batch.py` 和 `app.py` 以支援主題切換
76
+ 3. **第 3 階段**:實現 localStorage 持久化邏輯
77
+ 4. **第 4 階段**:測試 Plotly 圖表在深色模式下的正確呈現
78
+ 5. **第 5 階段**:部署至 Hugging Face Spaces 和本地環境
79
+
80
+ ### 回滾策略
81
+ - 若發生主題相關錯誤,用戶可清除瀏覽器 localStorage 以還原預設亮色模式
82
+ - 亮色模式始終作為備選方案保持可用
83
+ - 無需資料遷移或後端回滾
84
+
85
+ ## Open Questions
86
+
87
+ 1. 深色模式的預設顏色方案是否應該支援用戶的系統偏好設定偵測(`prefers-color-scheme` CSS Media Query)?
88
+ 2. Gradio 版本升級時,主題系統的相容性如何確保?
89
+ 3. 是否需要為深色模式提供額外的協助工具(無障礙性)測試?
openspec/changes/archive/2026-03-10-add-dark-mode/proposal.md ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## 為什麼
2
+
3
+ 使用股票分析工具的用戶經常在清晨或晚間交易時段的低光環境中操作。目前僅有亮色模式的介面會導致眼睛疲勞,降低可用性。新增深色模式可以改善用戶體驗、減少長時間使用時的眼睛負擔,並符合現代網頁應用程式的標準。
4
+
5
+ ## 變更內容
6
+
7
+ - 在 Gradio 介面標題欄新增主題切換按鈕(亮色/深色)
8
+ - 定義 CSS 變數和 Gradio 深色模式主題配置,使用適當的顏色方案
9
+ - 將用戶的主題偏好設定儲存到瀏覽器 localStorage 或伺服器端配置
10
+ - 在應用程式啟動時根據用戶偏好或系統設定自動套用深色模式
11
+ - 更新所有 Gradio 元件(圖表、表格、輸入框)以支援主題切換
12
+ - 確保 Plotly 圖表在深色模式下具有足夠的色彩對比度並正確呈現
13
+
14
+ ## 功能模塊
15
+
16
+ ### 新增功能模塊
17
+
18
+ - `theme-toggle-ui`:提供主題切換控制項(按鈕/下拉選單),讓用戶能即時在亮色和深色模式之間切換
19
+ - `theme-persistence`:儲存用戶的主題偏好設定,在下次啟動應用程式時自動套用
20
+ - `dark-mode-styling`:提供深色模式的 CSS 和 Gradio 主題配置,確保足夠的色彩對比度和可讀性
21
+ - `chart-theme-support`:確保 Plotly 視覺化圖表(長條圖、散布圖、雷達圖、圓餅圖)在亮色和深色模式下均能正確呈現
22
+
23
+ ### 修改現有功能模塊
24
+
25
+ <!-- 現有功能模塊的規格層級沒有變更 -->
26
+
27
+ ## 影響範圍
28
+
29
+ - **修改檔案**:`app_batch.py`、`app.py`(Gradio 應用程式初始化和主題處理)
30
+ - **新增檔案**:`css/dark_mode.css`、`theme_config.py`(或在現有檔案中新增主題配置)
31
+ - **相依套件**:不需要新增外部套件(Gradio 原生支援主題功能)
32
+ - **API 變更**:無 API 變更;主題為客戶端/UI 層級功能
33
+ - **使用者體驗**:非破壞性變更;現有亮色模式保持預設值,深色模式為選擇性功能
34
+ - **部署支援**:支援 Hugging Face Spaces 和本地部署
openspec/changes/archive/2026-03-10-add-dark-mode/specs/chart-theme-support/spec.md ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: Plotly 圖表應在深色模式下正確渲染
4
+
5
+ Plotly 視覺化圖表(包括長條圖、散布圖、雷達圖、圓餅圖)應自動適配深色模式,確保可讀性和美觀性。
6
+
7
+ #### Scenario: 長條圖在深色模式中應有清晰的對比度
8
+ - **WHEN** 用戶在深色模式中查看長條圖
9
+ - **THEN** 圖表的色彩應清晰區分,背景應與數據條形形成足夠對比
10
+
11
+ #### Scenario: 散布圖在深色模式中應清晰顯示數據點
12
+ - **WHEN** 用戶在深色模式中查看散布圖
13
+ - **THEN** 數據點的顏色應在深色背景上清晰可見,不應混淆或難以區分
14
+
15
+ #### Scenario: 雷達圖在深色模式中應保持可讀性
16
+ - **WHEN** 用戶在深色模式中查看雷達圖
17
+ - **THEN** 網格線、數據線和標籤應清晰可讀,對比度應符合標準
18
+
19
+ #### Scenario: 圓餅圖在深色模式中應清晰顯示各部分
20
+ - **WHEN** 用戶在深色模式中查看圓餅圖
21
+ - **THEN** 各部分的顏色應區分清晰,並且對比度應足以區分相鄰的片段
22
+
23
+ ### Requirement: Plotly 圖表應與應用程式主題協調
24
+
25
+ 圖表的背景色、文字色、網格線色等應與應用程式整體主題相協調,避免視覺不和諧。
26
+
27
+ #### Scenario: 圖表背景應匹配應用程式背景
28
+ - **WHEN** 主題切換時
29
+ - **THEN** Plotly 圖表的背景色應自動更新以匹配應用程式的深色或亮色背景
30
+
31
+ #### Scenario: 圖表文字顏色應與背景形成對比
32
+ - **WHEN** 用戶查看圖表
33
+ - **THEN** 軸標籤、圖例、標題等文字應以與背景色形成足夠對比的顏色呈現
34
+
35
+ #### Scenario: 圖表網格線應在深色模式中可見
36
+ - **WHEN** 用戶在深色模式中查看圖表
37
+ - **THEN** 網格線應以適當顏色顯示(例如淺灰色),不應過於暗淡或不可見
38
+
39
+ ### Requirement: 圖表主題應無需頁面重新加載即時更新
40
+
41
+ 當用戶切換主題時,已渲染的圖表應立即更新其顏色方案。
42
+
43
+ #### Scenario: 主題切換時圖表顏色應即時改變
44
+ - **WHEN** 用戶點擊主題切換按鈕
45
+ - **THEN** 當前頁面上的所有 Plotly 圖表應立即更新其色彩以反映新主題
46
+
47
+ #### Scenario: 新渲染的圖表應使用當前主題配色
48
+ - **WHEN** 用戶在深色模式中執行操作導致新圖表被生成
49
+ - **THEN** 新圖表應自動使用深色主題配色,無需額外配置
openspec/changes/archive/2026-03-10-add-dark-mode/specs/dark-mode-styling/spec.md ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: 深色模式應有定義完整的顏色方案
4
+
5
+ 系統應提供深色模式的完整顏色定義,包括背景、文字、邊框、輸入框等所有 UI 元件的色彩。
6
+
7
+ #### Scenario: 深色模式背景為深色且文字為淺色
8
+ - **WHEN** 用戶切換至深色模式
9
+ - **THEN** 應用程式背景應為深色(例如 #1a1a1a 或類似顏色),文字應為淺色(例如 #f0f0f0)
10
+
11
+ #### Scenario: 所有 Gradio 元件應支援深色主題
12
+ - **WHEN** 用戶在深色模式中使用應用程式
13
+ - **THEN** 所有輸入框、按鈕、下拉選單、標籤等 Gradio 元件應適配深色配色
14
+
15
+ #### Scenario: 深色模式色彩應符合 WCAG 標準
16
+ - **WHEN** 檢查深色模式的色彩對比度
17
+ - **THEN** 所有文字與背景的對比度應至少達到 WCAG AA 級別(4.5:1 對於普通文字)
18
+
19
+ ### Requirement: 應使用 CSS 變數實現主題配置
20
+
21
+ 顏色方案應通過 CSS 變數定義,以便於維護和修改。
22
+
23
+ #### Scenario: CSS 變數定義亮色模式顏色
24
+ - **WHEN** 應用程式以亮色模式運行
25
+ - **THEN** CSS 變數(例如 `--bg-color`, `--text-color`)應設定為亮色值
26
+
27
+ #### Scenario: CSS 變數定義深色模式顏色
28
+ - **WHEN** 應用程式以深色模式運行
29
+ - **THEN** CSS 變數應設定為深色值,所有依賴這些變數的元素應自動更新
30
+
31
+ #### Scenario: Gradio 主題配置應與 CSS 變數同步
32
+ - **WHEN** 主題切換發生
33
+ - **THEN** Gradio 的原生主題系統應與 CSS 變數保持同步,確保一致的視覺效果
34
+
35
+ ### Requirement: 深色模式應包含強調色和次要色
36
+
37
+ 除了背景和文字顏色外,應定義強調色、邊框色、懸停狀態色等,確保完整的視覺層次。
38
+
39
+ #### Scenario: 按鈕在深色模式中應有適當的強調色
40
+ - **WHEN** 用戶在深色模式中查看按鈕
41
+ - **THEN** 按鈕應使用與深色背景形成良好對比的強調色
42
+
43
+ #### Scenario: 互動元素(懸停、焦點)應在深色模式中可見
44
+ - **WHEN** 用戶在深色模式中與元件互動(懸停、焦點)
45
+ - **THEN** 元件的狀態變化應清晰可見,例如懸停時顏色應改變
openspec/changes/archive/2026-03-10-add-dark-mode/specs/theme-persistence/spec.md ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: 用戶主題偏好應被持久化儲存
4
+
5
+ 系統應將用戶選擇的主題(亮色或深色)持久化儲存,以便在用戶下次訪問應用程式時能夠恢復此偏好。
6
+
7
+ #### Scenario: 用戶選擇深色模式並關閉應用程式
8
+ - **WHEN** 用戶切換至深色模式並關閉瀏覽器標籤頁
9
+ - **THEN** 用戶的主題選擇應被儲存
10
+
11
+ #### Scenario: 用戶在新會話中恢復其主題偏好
12
+ - **WHEN** 用戶在新的瀏覽器會話中訪問應用程式
13
+ - **THEN** 應用程式應自動應用用戶先前選擇的主題(深色模式)
14
+
15
+ #### Scenario: 新用戶看到預設亮色模式
16
+ - **WHEN** 新用戶首次訪問應用程式且無儲存偏好
17
+ - **THEN** 應用程式應默認顯示亮色模式
18
+
19
+ ### Requirement: 主題偏好應存儲在瀏覽器 localStorage 中
20
+
21
+ 儲存機制應優先使用瀏覽器的 localStorage API 以實現跨會話持久化,並在 localStorage 不可用時提供備選方案。
22
+
23
+ #### Scenario: 應用程式使用 localStorage 儲存主題選擇
24
+ - **WHEN** 用戶切換主題
25
+ - **THEN** 系統應將主題選擇寫入瀏覽器 localStorage(例如鍵名為 `theme-preference`)
26
+
27
+ #### Scenario: 應用程式從 localStorage 讀取儲存的偏好
28
+ - **WHEN** 應用程式啟動
29
+ - **THEN** 系統應檢查 localStorage 中是否存在 `theme-preference` 鍵並相應地應用主題
30
+
31
+ #### Scenario: 當 localStorage 不可用時應有備選方案
32
+ - **WHEN** 瀏覽器的 localStorage 被禁用或不可用
33
+ - **THEN** 系統應回退至預設亮色模式,用戶仍可手動切換主題(該會話內生效)
34
+
35
+ ### Requirement: 應支援系統偏好設定自動偵測(可選)
36
+
37
+ 系統可以選擇性地偵測用戶的作業系統主題偏好設定(如果 localStorage 中沒有用戶選擇)。
38
+
39
+ #### Scenario: 首次訪問時偵測系統深色模式偏好
40
+ - **WHEN** 新用戶首次訪問且系統設定為深色模式
41
+ - **THEN** 應用程式可選擇自動應用深色模式(基於 CSS Media Query `prefers-color-scheme`)
42
+
43
+ #### Scenario: 用戶明確選擇覆蓋系統偏好
44
+ - **WHEN** 用戶手動切換主題
45
+ - **THEN** 用戶的選擇應儲存並優先於系統偏好
openspec/changes/archive/2026-03-10-add-dark-mode/specs/theme-toggle-ui/spec.md ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: 主題切換按鈕在 UI 標題欄中可見
4
+
5
+ 系統應在 Gradio 應用程式的標題欄(preferably 右側)顯示一個主題切換控制項。該控制項應直觀指示當前主題(亮或深)並允許用戶點擊以切換。
6
+
7
+ #### Scenario: 用戶在亮色模式中看到深色模式選項
8
+ - **WHEN** 用戶首次打開應用程式(預設亮色模式)
9
+ - **THEN** UI 標題欄右側應顯示一個「深色模式」按鈕或圖標
10
+
11
+ #### Scenario: 用戶點擊按鈕切換到深色模式
12
+ - **WHEN** 用戶點擊標題欄中的主題切換按鈕
13
+ - **THEN** 應用程式整個 UI 應立即切換到深色模式
14
+
15
+ #### Scenario: 用戶在深色模式中看到亮色模式選項
16
+ - **WHEN** 用戶已切換至深色模式
17
+ - **THEN** UI 標題欄中的按鈕應更新,顯示「亮色模式」選項
18
+
19
+ #### Scenario: 用戶點擊按鈕切換回亮色模式
20
+ - **WHEN** 用戶在深色模式中點擊主題切換按鈕
21
+ - **THEN** 應用程式整個 UI 應立即切換回亮色模式
22
+
23
+ ### Requirement: 主題切換控制項應具有可存取性
24
+
25
+ 控制項應遵循網頁無障礙指南(WCAG),包括適當的 ARIA 標籤、鍵盤導航支援和對比度要求。
26
+
27
+ #### Scenario: 用戶可通過鍵盤導航至主題切換按鈕
28
+ - **WHEN** 用戶使用 Tab 鍵導航
29
+ - **THEN** 主題切換按鈕應在標籤順序中且可通過 Enter/Space 啟動
30
+
31
+ #### Scenario: 螢幕閱讀器用戶可理解控制項的目的
32
+ - **WHEN** 螢幕閱讀器掃描 UI
33
+ - **THEN** 控制項應有清晰的 ARIA 標籤,例如「切換深色/亮色模式」
34
+
35
+ ### Requirement: 主題切換應立即生效
36
+
37
+ 不應有延遲或頁面重新加載。UI 應平滑地過渡至新主題。
38
+
39
+ #### Scenario: 主題切換不需要頁面重新加載
40
+ - **WHEN** 用戶點擊主題切換按鈕
41
+ - **THEN** 主題應立即改變,無需重新加載頁面
42
+
43
+ #### Scenario: 所有 UI 元素應在不刷新的情況下更新
44
+ - **WHEN** 主題切換發生
45
+ - **THEN** 所有 Gradio 元件、圖表和文字應同步更新至新主題
openspec/changes/archive/2026-03-10-add-dark-mode/tasks.md ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## 1. 設置和基礎配置
2
+
3
+ - [x] 1.1 建立 `theme_config.py` 檔案,定義亮色和深色主題的顏色變數
4
+ - [x] 1.2 建立 `css/dark_mode.css` 檔案,使用 CSS 變數定義主題樣式
5
+ - [x] 1.3 在 `requirements.txt` 中確認 Gradio 版本被固定(如尚未固定)
6
+
7
+ ## 2. 實現主題儲存機制
8
+
9
+ - [x] 2.1 建立 localStorage 相關的 JavaScript 程式碼,用於儲存和讀取主題偏好設定
10
+ - [x] 2.2 實現伺服器端預設值或備選機制,當 localStorage 不可用時使用
11
+ - [x] 2.3 測試主題偏好設定在跨會話中的持久化
12
+
13
+ ## 3. 實現主題切換 UI 控制項
14
+
15
+ - [x] 3.1 在 `app_batch.py` 中的 Gradio 標題欄新增主題切換按鈕
16
+ - [x] 3.2 在 `app.py` 中的 Gradio 標題欄新增主題切換按鈕(保持一致)
17
+ - [x] 3.3 為按鈕新增 ARIA 標籤和鍵盤導航支援
18
+ - [x] 3.4 實現按鈕的點擊事件處理,觸發主題切換
19
+
20
+ ## 4. 實現深色模式樣式應用
21
+
22
+ - [x] 4.1 在 `app_batch.py` 中整合 Gradio 主題配置,支援亮色和深色模式
23
+ - [x] 4.2 在 `app.py` 中整合 Gradio 主題配置,支援亮色和深色模式
24
+ - [x] 4.3 確保 CSS 變數在主題切換時正確應用到所有 UI 元件
25
+ - [x] 4.4 驗證所有顏色對比度符合 WCAG AA 標準
26
+
27
+ ## 5. 實現 Plotly 圖表主題支援
28
+
29
+ - [x] 5.1 修改圖表生成函式,在建立時基於當前主題應用 Plotly 配置
30
+ - [x] 5.2 為 Plotly 定義亮色和深色兩種主題樣板
31
+ - [x] 5.3 實現主題切換時 Plotly 圖表的即時重新渲染
32
+ - [x] 5.4 在長條圖、散布圖、雷達圖、圓餅圖中測試深色模式配色
33
+
34
+ ## 6. 整合應用程式啟動邏輯
35
+
36
+ - [x] 6.1 在應用程式啟動時讀取儲存的主題偏好設定
37
+ - [x] 6.2 實現系統偏好設定自動偵測(使用 CSS Media Query `prefers-color-scheme`)
38
+ - [x] 6.3 確保首次訪問用戶預設使用亮色模式
39
+
40
+ ## 7. 測試和驗證
41
+
42
+ - [x] 7.1 測試主題切換按鈕的可見性和可存取性(螢幕閱讀器、鍵盤導航)
43
+ - [x] 7.2 測試主題偏好設定在亮色和深色模式之間的持久化
44
+ - [x] 7.3 測試所有 Gradio 元件在深色模式下的正確呈現
45
+ - [x] 7.4 測試所有 Plotly 圖表在深色模式下的顏色對比度和可讀性
46
+ - [x] 7.5 驗證無需頁面重新加載的即時主題切換
47
+ - [ ] 7.6 在 Hugging Face Spaces 環境中測試深色模式功能
48
+
49
+ ## 8. 部署和文件
50
+
51
+ - [x] 8.1 更新 README 或文件,說明如何使用深色模式功能
52
+ - [x] 8.2 驗證深色模式在本地和 Hugging Face Spaces 中均能正常運作
53
+ - [x] 8.3 建立使用者回饋機制,收集深色模式的改進建議
openspec/config.yaml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ schema: spec-driven
2
+
3
+ # Project context
4
+ context: |
5
+ Project: StockRecommender - AI-powered stock analysis tool
6
+ Tech Stack: Python, Gradio (web UI), yfinance (market data), Transformers (FinBERT, BART)
7
+ Deployment: Hugging Face Spaces or local
8
+ Main Files: app_batch.py (advanced), app.py (simple), requirements.txt
9
+ Architecture: StockAnalyzer class for data/analysis, Plotly for visualizations
10
+ Conventions:
11
+ - Error handling: wrap external API calls (yfinance, HF) in try-except
12
+ - UI: Gradio components in Row/Column for layout
13
+ - Fallback models: use lightweight alternatives if memory constraints
14
+ - Runtime install: auto-install missing packages via install_package()
15
+ - Always update requirements.txt when adding dependencies
16
+ Key Patterns:
17
+ - ProsusAI/finbert for sentiment, facebook/bart-large-cnn for summarization
18
+ - Plotly for charts (Bar, Scatter, Radar, Pie)
19
+ - Batch analysis via text input or StockList.xlsx