一键导入
opsx-plan-to-issues
Convert an OpenSpec change's tasks.md into a plan.json and create a GitHub Issue for progress tracking
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Convert an OpenSpec change's tasks.md into a plan.json and create a GitHub Issue for progress tracking
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | opsx-plan-to-issues |
| description | Convert an OpenSpec change's tasks.md into a plan.json and create a GitHub Issue for progress tracking |
| metadata | {"category":"Workflow","tags":["workflow","artifacts","github","experimental"]} |
Convert one or more OpenSpec changes' tasks.md into plan.json files and create GitHub Issues with task checkboxes for visual progress tracking.
You are converting OpenSpec change task lists into structured JSON and GitHub Issues.
Scan the current project's openspec/changes/ directory for active changes (directories containing tasks.md that are NOT in archive/).
If no changes found: inform the user and suggest running /opsx-ff or /opsx-continue first.
If exactly one change found: announce it and proceed. The user can still cancel in the preview step.
If multiple changes found: use AskUserQuestion with multiSelect: true to let the user choose:
"Which change(s) should I create GitHub issues for?"
plan.json with a tracking_issue set (show them as "already has issue #N" in the list but don't make them selectable)Store the selected changes as {SELECTED_CHANGES}.
Determine the GitHub repository using this priority order:
project.md's Projects table under the "GitHub Repo" columngit remote get-url origin from the project directoryExtract the owner/repo (e.g., ConductionNL/nldesign). This will be stored in plan.json's repo field and used by /opsx-apply for all GitHub operations.
Determine the app name from the project directory name (e.g., nldesign, procest). This is used as a label on the GitHub issue.
For each selected change, read its tasks.md and extract each task into this JSON structure:
{
"change": "<change-name>",
"project": "<project-directory-name>",
"repo": "<owner/repo>",
"created": "<ISO-date>",
"tracking_issue": null,
"tasks": [
{
"id": 1,
"title": "<task title from ### Task N: header>",
"description": "<task description>",
"status": "pending",
"spec_ref": "<from spec_ref field in tasks.md>",
"acceptance_criteria": ["<from acceptance_criteria in tasks.md>"],
"files_likely_affected": ["<from files field in tasks.md>"]
}
]
}
Show the user a preview of all issues that will be created:
If single change:
About to create 1 GitHub issue in <owner/repo>:
📌 [OpenSpec] [<app-name>] <change-name>
Labels: openspec, <app-name>, <spec-1>, <spec-2>, ...
Tasks (as checkboxes in the issue body):
### 1. Section Name
- [ ] 1.1 task title
- [ ] 1.2 task title
### 2. Section Name
- [ ] 2.1 task title
...
If multiple changes:
About to create N GitHub issues in <owner/repo>:
1. 📌 [OpenSpec] [<app-name>] <change-1>
Labels: openspec, <app-name>, <spec-a>, <spec-b>
Tasks: X checkboxes
2. 📌 [OpenSpec] [<app-name>] <change-2>
Labels: openspec, <app-name>, <spec-c>
Tasks: Y checkboxes
...
Use AskUserQuestion to ask: "Create these N issue(s) in <owner/repo>?"
Options:
tasks.md files, then re-runDo NOT create any issues until confirmed.
plan.json already has tracking_issue)Before creating new issues, check each selected change for an existing tracking_issue in its plan.json. For changes that already track an issue, sync rather than create:
Fetch the live issue body: gh issue view <tracking_issue> --json body
Diff against tasks.md: compare task lines to checkboxes in the live body.
Update only unchecked tasks that are in tasks.md but absent from the issue:
tasks.md that is - [ ] but the live issue has - [x], leave as-is (the live issue is the source of human progress; do NOT regress checkboxes).tasks.md not in the issue at all, append them to the ## Tasks section.gh issue edit <tracking_issue> --body "<updated body>" or MCP update_issue.Report sync status — for each synced change, output:
#<num> <change-name>: synced N task(s) (X→checked, Y→unchanged)
If no diff, report synced 0 task(s) (already in sync).
Skip Step 4 for synced changes — they already have a tracking issue and don't need a new one. Continue to Step 4 only for changes WITHOUT tracking_issue.
Determine labels (once per change):
openspec — always present<app-name> — the project directory name (e.g., procest, nldesign)openspec/changes/<change-name>/specs/ for subdirectories; each subdirectory name becomes a label (e.g., if specs/lead-management/ and specs/pipeline-views/ exist, add labels lead-management and pipeline-views)Ensure all required labels exist (create if missing) — do this once before the loop, collecting all unique labels across all changes:
list_labels → {owner, repo} — check if each label exists; create missing ones with create_label → {owner, repo, name, color}existing_labels=$(gh api repos/<owner>/<repo>/labels --jq '.[].name' 2>/dev/null || echo "")
echo "$existing_labels" | grep -q "openspec" || gh api repos/<owner>/<repo>/labels --method POST -f name="openspec" -f color="0075ca" >/dev/null
echo "$existing_labels" | grep -q "<app-name>" || gh api repos/<owner>/<repo>/labels --method POST -f name="<app-name>" -f color="7057ff" >/dev/null
# For each spec label:
echo "$existing_labels" | grep -q "<spec-name>" || gh api repos/<owner>/<repo>/labels --method POST -f name="<spec-name>" -f color="d93f0b" >/dev/null
Label colors:
openspec: 0075ca (blue)<app-name>: 7057ff (purple)<spec-name>: d93f0b (red)For each selected change, create the issue:
[OpenSpec] [<app-name>] <change-name>proposal.md, followed by a ## Tasks section with task checkboxes grouped under section headers from tasks.mdcreate_issue → {owner, repo, title: "[OpenSpec] [<app-name>] <change-name>", body: "<body>", labels: ["openspec", "<app-name>", "<spec-1>", "<spec-2>", ...]} — returns {number, html_url}, capture number directlygh issue create --repo <owner/repo> --title "[OpenSpec] [<app-name>] <change-name>" --body "<body>" --label "openspec,<app-name>,<spec-1>,<spec-2>" — parse issue number from returned URLIssue body structure:
<summary from proposal.md>
## Specs
<list of delta spec names with brief description from each spec>
## Tasks
### 1. Section Name
- [ ] **1.1 Task title**
- [ ] Acceptance criterion 1
- [ ] Acceptance criterion 2
- [ ] **1.2 Task title**
- [ ] Acceptance criterion 1
### 2. Section Name
- [ ] **2.1 Task title**
- [ ] Acceptance criterion 1
For each change, update its plan.json with the created issue number (tracking_issue) and save at openspec/changes/<change-name>/plan.json in the project directory.
Output a summary:
If single change:
If multiple changes:
## Issues Created
| Change | Issue | Tasks | Labels |
|--------|-------|-------|--------|
| <change-1> | #N (<url>) | X tasks | openspec, <app>, <spec-a> |
| <change-2> | #M (<url>) | Y tasks | openspec, <app>, <spec-c> |
If invoked from an orchestrating skill (the caller will have said something like "Invoked from apply-loop — skip Step 6 AskUserQuestion and return control"): output the summary, then output exactly: ✅ plan-to-issues complete — NEXT STEP: immediately continue to Step 3 of apply-loop without pausing. Stop immediately. Do NOT use AskUserQuestion.
Otherwise, use AskUserQuestion to ask:
"Issue(s) created! What would you like to do next?"
Options:
/opsx-apply) — begin working through the tasksCapture Learnings
After execution, review what happened and append new observations to learnings.md under the appropriate section:
Each entry must include today's date. One insight per bullet. Skip if nothing new was learned.
Guardrails
tasks.md does not exist for a change — skip that change and warngh is not authenticated (gh auth status fails), inform the user and stopgh api repos/<owner>/<repo>/labels to list them; handles repos with zero labels)plan.json already has a tracking_issue, skip it and warnReset the OpenRegister development environment (stop, remove volumes, restart, install apps)
Create a Pull Request from the current branch — runs local checks, picks target branch, and opens the PR on GitHub
Analyze a project's OpenSpec from 8 persona perspectives and suggest additional features
Detect admin settings Vue components registered in the vue-router. Admin settings are rendered by Nextcloud's settings framework via `AdminSettings.php`; adding their Vue components to the in-app router exposes them as publicly-accessible frontend routes, bypassing all server-side access checks. ADR-004 hard rule. Observed 2026-04-30 on doriath where `/settings → AdminRoot` was a route in `src/router/index.js` (commit c7c72e9).
Run `composer audit` to check composer.lock dependencies for known CVEs. Invoked by the builder before push and the reviewer's mandatory block. Mirrors the orchestrator's `composer-audit` quality gate.
Scan lib/ for forbidden debug helpers (var_dump / die / error_log / print_r / dd / dump) that should not ship. Invoked by the builder before push, by the reviewer as Mandatory Step 2, and by the fixer during a retry. Mirrors the orchestrator's `forbidden-patterns` quality gate.