关于 oh-my-issues
用于 GitHub 问题管理的技能,按架构根因归并相关症状,并将每个问题簇作为计划跟踪。支持积压整理、持续分诊,以及将成组修复打包到一次 PR 中关闭相关问题。
主要功能
- 01按共同根因聚类问题
- 02创建计划主问题和设计文档
- 03将新缺陷归入现有计划
- 04将一组修复打包为一个 PR
- 05定义积压健康检查和停止条件
适用场景
- 01整理大量待处理问题
- 02将新缺陷归入现有计划
- 03准备一次性解决相关问题的 PR
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ thedotmack/ claude-mem --skill oh-my-issues安装后在 Claude Code 中输入/oh-my-issues确认已加载。
详细介绍
oh-my-issues
将问题积压转化为路线图。问题是症状数据,不是工作单元——工作单元是产生这些问题的架构缺陷。最终状态是 open issues == open plans,一一对应。
核心原则
不要再一次只关闭一个问题。将由同一项架构修复解决的症状归为一个集群,为该集群指定一个规范归属(一个主计划问题 + 一个 plans/0X-*.md 设计文档),用标准化的重定向评论关闭所有子问题,并为每个集群提交一个一次性关闭所有子问题的 PR。新提交的 Bug 应以“Round N”评论追加到匹配的主问题中,而不是作为新的跟踪问题创建。
这样会带来三重累积效应:架构修复会消除整个症状家族,计划中的测试矩阵会将预防措施纳入 CI,标准化分诊则会降低后续问题流入的处理成本。
适用场景
- 仓库有 20 个以上未关闭的问题,其中许多看起来像重复问题,或是同一缺陷在特定平台上的症状。
- 用户要求对问题列表进行“分诊”“整合”“聚类”“去重”“分组”或“制定计划”。
- 有新的 Bug 被提交,用户想知道它是否属于现有工作。
- 用户想提交一个有明确范围、能解决一组相关问题的 PR。
不适用场景
- 未关闭的问题少于约 15 个:直接关闭即可。
- 问题确实相互独立(没有共同根因):每个问题单独修复才是正确做法。
- 仓库没有使用
plans/的惯例,且用户不想引入这一惯例——应先提出建议,不要强行推行。
三种模式
模式 1:集群梳理(初步精简)
适用于积压问题从未经过整合的情况。目标:通过一次操作,将 N 个问题精简为 N_plans 个主问题。
- 完整阅读所有内容。 获取每个未关闭问题的正文和评论串,而不只是标题。没有完整文本,表面分组就会失效;复现步骤、关联的重复问题和诊断输出往往在评论中,而不是原始正文中。正确的分页列表获取方式和逐个问题获取评论的方法见下文“GitHub CLI 基本命令”(单次调用
gh issue list不会返回评论正文)。 - 按根因聚类,而不是按表象聚类。 聚类时要问的是一次架构变更能否消除所有这些问题?,而不是这些问题是否提到了同一个词?。“Windows”是表象;“宿主 Shell 违反了 spawn 合约”才是根因。表象不同的两个问题也可能属于同一集群(例如,两条不同代码路径中的环境变量泄漏,都源于缺少环境隔离边界)。
- 将每个集群命名为一个架构问题。 标题格式:
[plan-XX] <Architectural Defect> — <one-line scope>。示例:[plan-02] Spawn-Contract Templating — canonical ${CLAUDE_PLUGIN_ROOT} resolution across all hosts。标题必须体现修复方案,而不是描述主题。 - 为每个集群创建一个主问题,其正文应列出:架构缺陷、子问题(按问题编号)、修复步骤,以及防止回归所需的测试矩阵(宿主 × IDE × Shell 等)。
- 在仓库中将每个主问题对应为
plans/0X-<slug>.md。问题是公开跟踪记录;文档是设计方案。两者应相互引用。 - 用标准化的重定向评论关闭每个子问题(见下文),并标注
not planned。 - 验证最终状态:
gh issue list --state open应只返回主问题,不包含其他内容。
对于约 100 个问题,目标结构为:4–8 个主问题。超过 10 个,说明你按表象聚类了;少于 3 个,说明集群范围过大,无法各自通过一个 PR 完成交付。
模式 2:分类处理(新收到的 Bug,稳定阶段)
当完成归并后有新 Issue 提交时使用。目标:不让 Issue 列表再次累积。
- 完整阅读新 Issue 的正文。
- 将症状与现有计划主 Issue 进行模式匹配。 对于每个未关闭的主 Issue,问自己:这里描述的修复也能修复这个新 Bug 吗? 如果可以 → 将它归入该计划。
- 如果存在匹配项,在主 Issue 上发布一条“第 N 轮”评论,其中:
- 按编号指出新的子 Issue
- 用一行描述症状
- 概述具体修复方案(1–3 行,例如“使用
case "$_SH" in /*.exe|"") _SH=bash ;; esac进行保护”) - 补充该 Bug 揭示的任何新测试矩阵单元
- 使用标准重定向评论关闭子 Issue,并标记为
not planned。 - 如果没有匹配项且该 Bug 确实是全新的:创建新的计划主 Issue +
plans/0X-*.md。尽量避免这样做。大多数 Bug 都是现有计划的子 Issue。
模式 3:打包(交付问题簇)
当某个计划切片已准备好交付时使用。目标:一个 PR 原子性地关闭 N 个子 Issue。
- 列出主 Issue 的子 Issue。 从主 Issue 正文和归并评论中收集所有归入此计划的子 Issue 编号。
- 确认架构修复覆盖了每个子 Issue 的症状。 如果有子 Issue 未被覆盖,则 PR 尚未准备好,或者该子 Issue 应归入其他计划。
- 生成 PR 描述:标题为计划切片(例如“fix(spawn): canonical ${CLAUDE_PLUGIN_ROOT} resolution”);正文列出每个子 Issue,并使用
Closes #N,以便 GitHub 在合并时自动关闭它们。 - 在同一个 PR 中将计划里的测试矩阵添加到 CI。 没有测试矩阵,问题簇就会再次出现。
- 合并后,只有在所有子 Issue 都已覆盖时,才能关闭主 Issue。如果计划还有剩余范围,则保持主 Issue 未关闭,并链接该 PR,作为部分交付检查点。
为计划主 Issue 命名
计划主 Issue 的标题必须体现其修复内容。
| 不佳(表面问题) | 良好(架构层面) |
|---|---|
| Windows Bug | 跨主机 Spawn 契约模板化 |
| Worker 崩溃 | Worker / Daemon 生命周期加固 — 监督、健康检查、重试 |
| 认证问题 | Worker 环境隔离 — 从 SDK 子进程中剔除宿主 CLI 环境变量 |
| 安装失败 | 安装器故障透明化 — 跨 IDE 错误分类 + 12×4 测试矩阵 |
如果你无法用一行写出架构层面的范围,说明这个问题簇划分有误。
标准重定向评论
关闭每个子 Issue 时都使用以下确切措辞。保持一致,能让贡献者一眼识别出这一模式,并使审计记录可搜索。
Consolidating into #<MASTER> (plan-XX). The root cause and fix sequencing are tracked there alongside the rest of the cluster — please follow that issue for progress.
关闭时标记为 not planned(而非 completed)——子 Issue 是一种症状,而不是一个工作单元。
GitHub CLI 基础命令
解析仓库:
repo_json=$(gh repo view --json owner,name)
owner=$(jq -r '.owner.login // .owner.name' <<<"$repo_json")
repo=$(jq -r '.name' <<<"$repo_json")
列出所有未关闭的 Issue(全面读取阶段)。注意两点:
gh issue list --json comments只会返回一个计数占位符,而不会返回评论正文。必须使用gh issue view <N> --json comments按 Issue 获取评论。- 如果积压数量更多,显式设置的
--limit会静默截断结果。始终先检查未关闭 Issue 的总数。
# 1. Confirm total — never trust an arbitrary --limit.
# Note: GitHub's REST API treats PRs as issues, so .open_issues_count
# from /repos/{owner}/{repo} is actually issues + PRs. Use the search
# API to get the issue-only count.
total=$(gh api "search/issues?q=repo:$owner/$repo+is:issue+is:open" --jq '.total_count')
echo "Open issues: $total"
# 2. List bodies (set --limit at or above the true total)
gh issue list --state open --limit "$total" \
--json number,title,body,labels,author,createdAt
# 3. For each issue, fetch its full comment thread
for n in $(gh issue list --state open --limit "$total" --json number --jq '.[].number'); do
echo "=== Issue #$n ==="
gh issue view "$n" --json comments \
--jq '.comments[] | "\(.author.login) (\(.createdAt)): \(.body)"'
done
如果 total > 1000,请通过 REST API 分页:循环调用 gh api "repos/$owner/$repo/issues?state=open&per_page=100&page=N",直到结果数组为空(注意,这会包含 PR,因此要使用 select(.pull_request|not) 进行筛选)。
创建计划主 Issue:
gh issue create \
--title "[plan-02] Spawn-Contract Templating — canonical \${CLAUDE_PLUGIN_ROOT} resolution across all hosts" \
--body-file plans/02-spawn-contract-templating.md \
--label plan,plan-02
发布归并评论并关闭子 Issue:
gh issue comment <CHILD> --body "Consolidating into #<MASTER> (plan-XX). The root cause and fix sequencing are tracked there alongside the rest of the cluster — please follow that issue for progress."
gh issue close <CHILD> --reason "not planned"
向主 Issue 追加一条“第 N 轮”分类评论:
gh issue comment <MASTER> --body "$(cat <<'EOF'
**Round N consolidation**
- #<CHILD> (<one-line symptom>) folded into this plan as <classification>.
Proposed fix: <1–3 line sketch>.
Adds matrix cell: <host/IDE/shell combination>.
EOF
)"
验证最终状态:
gh issue list --state open --json number,title \
| jq -r '.[] | "\(.number)\t\(.title)"'
输出应仅包含计划主 Issue。
计划主 Issue 正文模板
保存为 plans/0X-<slug>.md,并将其用作主 Issue 的 --body-file。
# [plan-XX] <Architectural Defect> — <one-line scope>
## Defect
<One paragraph: what is structurally broken, why it produces the observed family of symptoms.>
## Children
- #N — <symptom one-liner>
- #N — <symptom one-liner>
- ...
## Fix sequence
1. <First architectural change — bounded, reviewable>
2. <Second>
3. ...
## Test matrix
| Axis A | Axis B | Required behavior |
|---|---|---|
| ... | ... | ... |
The matrix lives in CI. A future regression must fail CI before a user can file.
## Out of scope
<What this plan deliberately does not cover, with pointers to other plan masters.>
健康检查
定期对计划主问题进行检查,以发现故障模式。
- 墓地式主问题: 主问题已累计 5 条或更多“Round N”评论,却没有已交付的 PR。该计划需要一个强制推进的 PR,否则就必须拆分。
- 范围过广的主问题: 子问题的修复无法纳入一个 PR。将其拆分为两个范围更窄的计划。
- 按表面特征聚类的主问题: 子问题主题相同,但修复方式不同。按根本原因重新聚类;部分子问题应归入不同计划。
- 问题与文档不一致: 计划主问题正文与
plans/0X-*.md不一致。选定一个作为规范版本(文档),并据此重新生成问题正文。
停止条件
对于聚类处理:当 gh issue list --state open 恰好只返回主问题时,停止。
对于分诊:当新子问题已关闭,且主问题中有一条 Round-N 记录时,停止。
对于打包处理:当 PR 已合并,且所有列出的子问题都因 Closes #N 而自动关闭时,停止。
应拒绝的故障模式
- 未完整阅读每个问题正文就过早聚类。 不要这样做。
- 主问题尚未开启就关闭子问题。 子问题必须始终有一个重定向目标。
- 对并非症状的问题使用重定向评论(例如,没有共同根本原因的真实功能请求)。这类问题应保持开启,或走各自的处理流程。
- 所有列出的子问题尚未交付就关闭主问题。 主问题是约定;过早关闭会破坏审计记录。