mcpField
O
oh-my-issues

oh-my-issues

github.com/thedotmack开发104.0k4.1k 次安装今天更新
代码仓库

关于 oh-my-issues

用于 GitHub 问题管理的技能,按架构根因归并相关症状,并将每个问题簇作为计划跟踪。支持积压整理、持续分诊,以及将成组修复打包到一次 PR 中关闭相关问题。

主要功能

  1. 01按共同根因聚类问题
  2. 02创建计划主问题和设计文档
  3. 03将新缺陷归入现有计划
  4. 04将一组修复打包为一个 PR
  5. 05定义积压健康检查和停止条件

适用场景

  1. 01整理大量待处理问题
  2. 02将新缺陷归入现有计划
  3. 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 个主问题。

  1. 完整阅读所有内容。 获取每个未关闭问题的正文和评论串,而不只是标题。没有完整文本,表面分组就会失效;复现步骤、关联的重复问题和诊断输出往往在评论中,而不是原始正文中。正确的分页列表获取方式和逐个问题获取评论的方法见下文“GitHub CLI 基本命令”(单次调用 gh issue list 不会返回评论正文)。
  2. 按根因聚类,而不是按表象聚类。 聚类时要问的是一次架构变更能否消除所有这些问题?,而不是这些问题是否提到了同一个词?。“Windows”是表象;“宿主 Shell 违反了 spawn 合约”才是根因。表象不同的两个问题也可能属于同一集群(例如,两条不同代码路径中的环境变量泄漏,都源于缺少环境隔离边界)。
  3. 将每个集群命名为一个架构问题。 标题格式:[plan-XX] <Architectural Defect> — <one-line scope>。示例:[plan-02] Spawn-Contract Templating — canonical ${CLAUDE_PLUGIN_ROOT} resolution across all hosts。标题必须体现修复方案,而不是描述主题。
  4. 为每个集群创建一个主问题,其正文应列出:架构缺陷、子问题(按问题编号)、修复步骤,以及防止回归所需的测试矩阵(宿主 × IDE × Shell 等)。
  5. 在仓库中将每个主问题对应为 plans/0X-<slug>.md。问题是公开跟踪记录;文档是设计方案。两者应相互引用。
  6. 用标准化的重定向评论关闭每个子问题(见下文),并标注 not planned。
  7. 验证最终状态: gh issue list --state open 应只返回主问题,不包含其他内容。

对于约 100 个问题,目标结构为:4–8 个主问题。超过 10 个,说明你按表象聚类了;少于 3 个,说明集群范围过大,无法各自通过一个 PR 完成交付。

模式 2:分类处理(新收到的 Bug,稳定阶段)

当完成归并后有新 Issue 提交时使用。目标:不让 Issue 列表再次累积。

  1. 完整阅读新 Issue 的正文。
  2. 将症状与现有计划主 Issue 进行模式匹配。 对于每个未关闭的主 Issue,问自己:这里描述的修复也能修复这个新 Bug 吗? 如果可以 → 将它归入该计划。
  3. 如果存在匹配项,在主 Issue 上发布一条“第 N 轮”评论,其中:
    • 按编号指出新的子 Issue
    • 用一行描述症状
    • 概述具体修复方案(1–3 行,例如“使用 case "$_SH" in /*.exe|"") _SH=bash ;; esac 进行保护”)
    • 补充该 Bug 揭示的任何新测试矩阵单元
  4. 使用标准重定向评论关闭子 Issue,并标记为 not planned。
  5. 如果没有匹配项且该 Bug 确实是全新的:创建新的计划主 Issue + plans/0X-*.md。尽量避免这样做。大多数 Bug 都是现有计划的子 Issue。
模式 3:打包(交付问题簇)

当某个计划切片已准备好交付时使用。目标:一个 PR 原子性地关闭 N 个子 Issue。

  1. 列出主 Issue 的子 Issue。 从主 Issue 正文和归并评论中收集所有归入此计划的子 Issue 编号。
  2. 确认架构修复覆盖了每个子 Issue 的症状。 如果有子 Issue 未被覆盖,则 PR 尚未准备好,或者该子 Issue 应归入其他计划。
  3. 生成 PR 描述:标题为计划切片(例如“fix(spawn): canonical ${CLAUDE_PLUGIN_ROOT} resolution”);正文列出每个子 Issue,并使用 Closes #N,以便 GitHub 在合并时自动关闭它们。
  4. 在同一个 PR 中将计划里的测试矩阵添加到 CI。 没有测试矩阵,问题簇就会再次出现。
  5. 合并后,只有在所有子 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 而自动关闭时,停止。

应拒绝的故障模式

  • 未完整阅读每个问题正文就过早聚类。 不要这样做。
  • 主问题尚未开启就关闭子问题。 子问题必须始终有一个重定向目标。
  • 对并非症状的问题使用重定向评论(例如,没有共同根本原因的真实功能请求)。这类问题应保持开启,或走各自的处理流程。
  • 所有列出的子问题尚未交付就关闭主问题。 主问题是约定;过早关闭会破坏审计记录。

评论

支持 Markdown