分析用户的 Plannotator 计划存档,提取拒绝模式、反馈分类、随时间演变的情况以及可操作的提示改进,并生成精美的 HTML 仪表板报告。当 Plannotator 数据不可用时,回退到 Claude Code ExitPlanMode 的拒绝原因。
复合计划分析
您正在对用户的 Plannotator 计划存档进行全面研究分析。目标:从被拒绝的计划中提取模式,将其归纳为可操作的见解,并生成优雅的 HTML 仪表板报告。
这是一个多阶段过程。每个阶段必须完全完成后才能开始下一个阶段。研究完整性至关重要——每个文件都必须读取,不得跳过。
源选择
在开始分析之前,确定可用的数据源。
-
Plannotator 模式(首选) — 确定 Plannotator 数据目录:如果设置了
$PLANNOTATOR_DATA_DIR则使用该变量,否则使用~/.plannotator。检查该目录下的plans/子目录。如果存在且包含*-denied.md文件,则使用此模式。以下整个工作流程均针对 Plannotator 数据编写。 -
Claude Code 回退模式 — 如果 Plannotator 存档不存在或不包含被拒绝的计划,请检查
~/.claude/projects/。如果存在,请在继续之前阅读 references/claude-code-fallback.md。该参考文件解释了如何使用捆绑的解析器 scripts/extract_exit_plan_mode_outcomes.py 从 Claude Code JSONL 转录中提取拒绝原因。下面的每个阶段都有一个简短的说明,解释回退模式下的变化——参考文件中有详细信息。 -
两者都不可用 — 询问用户的 Plannotator 计划目录或 Claude Code 项目目录。不要猜测。
阶段 0:定位计划并检查之前的报告
使用上述源选择中选择的模式。
Plannotator 模式: 验证计划目录包含 *-denied.md 文件。如果不存在,则在停止之前回退到 Claude Code 模式。
Claude Code 回退模式: 根据回退参考运行捆绑的解析器以构建拒绝原因数据集。如果需要,创建 /tmp/compound-planning/。
无论哪种模式,都继续执行下面的“之前的报告检测”。
之前的报告检测
定位计划目录后,检查现有报告:
ls ${PLANNOTATOR_DATA_DIR:-~/.plannotator}/plans/compound-planning-report*.html
报告遵循版本化命名方案:
- 第一份报告:
compound-planning-report.html - 后续报告:
compound-planning-report-v2.html、compound-planning-report-v3.html等。
如果存在一个或多个报告,请确定最新的报告(版本号最高)。使用 stat 获取其文件系统修改日期(macOS:stat -f %Sm -t %Y-%m-%d,Linux:stat -c %y | cut -d' ' -f1)。这是截止日期。
向用户提供选择:
“我找到了一份之前的报告(
compound-planning-report-v{N}.html),最后更新于 {CUTOFF_DATE}。我可以:
- 增量 — 仅分析日期在 {CUTOFF_DATE} 之后的文件,节省令牌并基于之前的发现
- 完整 — 从头开始重新分析整个存档
您更喜欢哪个?”
等待用户回复后再继续。
如果是增量: 过滤所有后续阶段,仅处理日期在截止日期之后的文件。新报告版本将在其标题叙述中注明涵盖从 {CUTOFF_DATE} 到现在的期间,并引用之前的报告以获取早期发现。清单(阶段 1)仍应统计所有文件以获取总体统计数据,但应明确区分“自上次报告以来的新增”计数。
如果是完整: 正常处理所有文件,但输出文件名仍使用下一个版本号。
如果没有之前的报告: 正常进行。输出文件名将为 compound-planning-report.html(第一份报告没有版本后缀)。
阶段 1:清单
统计并报告数据集。始终统计所有文件以获取总体统计数据,无论这是增量运行还是完整运行:
- *-approved.md 文件(计数)
- *-denied.md 文件(计数)
- 日期范围(文件名中找到的最早到最晚日期)
- 总跨越天数
- 修订率:denied / (approved + denied) — 这是仪表板第 1 节中使用的“编码前修订的计划百分比”统计
注意: 完全忽略 *.annotations.md 文件。被拒绝的文件已包含完整的计划文本以及所有审阅者的反馈,这些反馈附加在 --- 分隔符之后。注释文件是此内容的冗余子集——同时读取两者会导致反馈重复计数。
如果是增量模式: 在总计数之后,分别报告仅截止日期之后文件的计数:
自 {CUTOFF_DATE} 以来的新增:
- *-denied.md 文件:X(共 Y 个)
- 新日期范围:{CUTOFF_DATE} 至 {LATEST_DATE}
- 新跨越天数:N
如果自截止日期以来新增的被拒绝文件少于 3 个,请警告用户:
“自上次报告以来只有 {N} 个新的被拒绝计划。增量分析可能内容较少。您想继续还是切换到完整分析?”
另外,对所有 *-approved.md 文件运行 wc -l,以获取每个已批准计划的平均行数。这可以告诉用户他们的计划是保持轻量还是随时间膨胀。您不需要阅读已批准计划的内容——只需它们的行数。如果可能,按时间段(例如每月)细分,以显示计划大小是否发生变化。
日期出现在文件名中,格式为 YYYY-MM-DD,有时作为前缀(2026-01-07-name-approved.md),有时嵌入(name-2026-03-15-approved.md)。从所有文件名中提取日期。
告诉用户您发现了什么,并且您正在开始提取。
Claude Code 回退模式: 上述 Plannotator 清单字段不适用。请改为按照 references/claude-code-fallback.md 中的清单说明操作——报告解析器构建的拒绝原因数据集。
阶段 2:映射——并行提取
这是最耗时的阶段。您必须读取范围内的每个 *-denied.md 文件。不要跳过文件。不要过早总结。
范围内意味着:如果运行完整分析,则所有被拒绝的文件;如果运行增量分析,则仅日期在截止日期之后的被拒绝文件。在增量模式下,仅处理其嵌入的 YYYY-MM-DD 日期严格在截止日期之后的文件。
Claude Code 回退模式: 解析器输出是干净的源数据集。阅读回退参考,了解特定于 JSON 部分文件的提取提示和批处理策略。除非解析器失败或用户要求审计级验证,否则不要返回原始 .jsonl 日志。
重要提示: 仅读取 *-denied.md 文件。不要阅读已批准的计划、注释文件或差异文件。每个被拒绝的文件包含完整的计划文本,后跟 --- 分隔符和审阅者的反馈——分析所需的一切都在一个文件中。
批处理策略
所有提取代理应使用 model: "haiku" — 它们执行简单的文件读取和结构化提取,不需要推理。Haiku 对于此类工作更快且更便宜。
方法取决于数据集大小:
微型数据集(≤ 10 个文件): 在主代理中直接读取所有文件——无需子代理。只需顺序读取它们并进入阶段 3。
小型数据集(11-30 个文件): 启动 2-3 个并行的 Haiku 代理,大致均匀地分配文件。
中型数据集(31-80 个文件): 启动 4-6 个并行的 Haiku 代理(每个约 10-15 个文件)。按文件类型和/或时间段拆分。
大型数据集(80+ 个文件): 启动尽可能多的并行 Haiku 代理,使每个批次保持在 10-15 个文件左右。按数据中的自然时间边界拆分(月、季度或任何能产生平衡批次的组合)。如果一个时间段占主导地位(例如,最近一个月有 3 倍的文件),则将该时间段拆分为多个批次。
使用 Agent 工具并行启动所有提取代理,设置 run_in_background: true 和 model: "haiku"。
输出文件
每个提取代理必须将其结果写入一个干净的输出文件,而不是依赖代理任务输出(其中包含难以解析的交错 JSONL 框架日志)。指示每个代理写入:
/tmp/compound-planning/extraction-{batch-name}.md
在启动代理之前创建 /tmp/compound-planning/ 目录。阶段 3 中的 reduce 代理将直接读取这些干净的文件。
提取提示
每个代理收到以下指令(调整时间段、文件列表和输出路径):
您正在从被拒绝的计划文件中提取结构化数据,用于模式分析。
目录:[PLANS DIRECTORY]
要读取的文件:[LIST OF SPECIFIC *-denied.md FILES]
输出:将您的完整结果写入 [OUTPUT FILE PATH]
每个被拒绝的文件包含由 --- 行分隔的两部分:
1. 计划文本(--- 之上)
2. 审阅者的反馈和注释(--- 之下)
读取列表中的每个文件。对于每个文件,提取:
- 计划名称/主题(来自 --- 之上的计划文本)
- 给出的拒绝原因或反馈(来自 --- 之下——捕获实际使用的词语)
- 具体要求更改的内容
- 反馈类型(让内容决定类别——不要强行放入预定义类型。常见类型包括:范围问题、方法分歧、信息缺失、流程要求、质量问题、用户体验/设计问题、命名争议、澄清请求、测试/程序性拒绝——但用户的实际模式可能不同)
- 审阅者使用的任何特定短语或重复语言
- 如果存在,则提取单个注释(带引号文本和审阅者评论的编号反馈项)
- 日期(从文件名中提取)
不要跳过任何文件。每个文件一个条目。
每个条目的格式:
**[filename]**
- 日期:...
- 主题:...
- 拒绝原因:...
- 反馈类型:...
- 具体要求:...
- 值得注意的短语:...
- 注释:[计数,每个的简要摘要]
---
处理完所有文件后,将完整结果写入 [OUTPUT FILE PATH]。在文件末尾说明总文件数。
代理运行时
跟踪完成情况。每个代理完成后,记下它处理的文件数。验证总数是否与阶段 1 中的清单匹配。如果任何代理的计数不足,请标记它并考虑为缺失的文件重新启动。
如果代理超时(对于大型批次可能发生——128 个文件的批次可能需要 8 分钟以上),则仅为未处理的文件重新启动它。检查输出文件以查看它在超时前处理到了哪里。
阶段 3:Reduce——模式分析
一旦所有提取代理完成(或对于微型数据集,所有文件都已读取),继续进行 reduce。Reduce 代理应使用 model: "sonnet" — 此阶段需要真正的分析推理,而不仅仅是文件读取。
Reduce 策略
方法取决于生成了多少个提取文件:
标准(≤ 20 个提取文件): 启动一个 Sonnet 代理来读取所有提取文件并生成完整分析。这涵盖了大多数数据集。
大型(21+ 个提取文件): 使用两阶段 reduce:
-
阶段 1 — 部分 reduce: 将提取文件分成 4-6 个一组。启动并行的 Sonnet 代理,每个代理读取一组并生成一个部分分析,包含下面列出的相同部分。每个代理写入
/tmp/compound-planning/partial-reduce-{N}.md。 -
阶段 2 — 最终 reduce: 一个 Sonnet 代理读取所有部分 reduce 文件,并将它们综合成最终的全面分析。此代理合并分类、组合计数、去重模式,并协调各部分之间任何冲突的分类。
Claude Code 回退模式: Reduce 阶段相同。唯一的上游区别是提取文件来自标准化的拒绝原因 JSON,而不是 Plannotator markdown 文件。
Reduce 提示
给每个 reduce 代理以下提示(针对单阶段与多阶段调整文件路径):
您是一名数据科学家,正在对用户的被拒绝计划存档进行 map-reduce 分析的 reduce 阶段。
读取 [FILE PATHS] 处的所有提取文件
这些文件包含来自每个被拒绝计划文件的结构化提取。每个提取包括计划主题、拒绝反馈、注释和审阅者语言。您的工作:汇总所有内容,找到模式,聚类成分类,并生成全面分析。
要详尽。使用真实计数。引用数据中的真实短语。这是研究——不要含糊其辞,不要捏造。
将您的完整结果写入 [OUTPUT FILE PATH]。
生成以下部分:
[... 下面列出的部分 ...]
Reduce 代理的工作是让数据说话。不要强加预定义的框架——发现实际存在的内容。分析必须生成:
1. 拒绝原因分类
将每个拒绝分类为从数据中出现的一组有限类型。计数出现次数。显示百分比。为每种类型包含真实的示例引用。目标是 8-15 个类别——足够具体,又足够少以便浏览。让用户的实际反馈决定类别是什么。
2. 主要反馈模式(按频率排序)
5-10 个最常出现的模式。对于每个模式:审阅者一致要求的内容,来自不同文件的 3 个以上示例引用,以及模式是否随时间变化。
3. 重复出现的短语
审阅者反复使用的确切短语,带有计数以及它们所指示的内容。这些是审阅者的词汇——他们关心的事物的简写。
4. 审阅者重视的内容(隐含偏好)
从模式中推导——这个特定的人最关心什么?质量?速度?叙述?架构?流程?简洁性?按证据强度排序。这部分应该感觉像是对审阅者标准的个性分析。
5. 代理经常出错的地方
另一面——哪些反复出现的错误会触发拒绝?对于这个审阅者,代理应该停止做什么?
6. 结构要求
审阅者一致要求什么样的计划结构?必需的章节、顺序、格式偏好、期望的详细程度。
7. 随时间演变
反馈模式如何随时间跨度变化。按数据中存在的自然时间边界分组(短跨度按周,较长跨度按月)。期望是否成熟?是否出现了新模式?发生了什么变化?如果数据集跨度少于一个月,请注意演变分析有限,但仍需寻找从早期到晚期文件的任何进展。
8. 可操作的提示指令
最重要的输出。基于所有模式:可以嵌入到规划提示中以防止最常见拒绝原因的具体编号指令。将这些写为代理可以遵循的实际指令。要针对此用户的模式具体化——像“写好计划”这样的通用建议毫无价值。每个指令都应追溯到真实的、频繁的拒绝模式。
编写指令后,计算它们能解决多大比例的拒绝(计算指令涵盖的类别中的拒绝数量与总拒绝数量之比)。报告此百分比——每个用户都会不同。
阶段 4:生成 HTML 仪表板
构建一个独立的 HTML 文件作为最终交付物。将其保存到用户的计划目录,使用版本化文件名:
- 第一份报告:
compound-planning-report.html - 第二份报告:
compound-planning-report-v2.html - 第三份报告:
compound-planning-report-v3.html - 依此类推。
版本号在阶段 0 中根据找到的现有报告确定。
如果这是增量报告,标题应指明分析期间(例如“2026 年 3 月 15 日 – 3 月 31 日”),并包含副标题注明“增量分析——早期发现请参见 v{N-1}”。第 1 节中的叙述应将发现框定为自上次报告以来的新增或变化,而不是完整图景。标题中的总体统计数据(文件计数、修订率)仍应反映完整存档以提供上下文。
阅读 assets/report-template.html 中的模板以获取设计语言。模板包含来自先前分析的示例数据——忽略模板中的所有数据值、引用和百分比。仅使用其视觉设计:颜色、排版、间距、组件样式和布局模式。
设计语言(来自模板)
- 调色板: 浅色模式,暖色米白 (#FDFCFB),文本使用石板色系,琥珀色用于高亮/强调,翡翠绿用于正面,玫瑰红用于负面,靛蓝用于操作元素
- 排版: Playfair Display(衬线,用于叙述性标题),Inter(无衬线,用于正文/数据),JetBrains Mono(等宽,用于代码/短语)——Google Fonts CDN
- 布局: 单列,最大宽度 1024px,慷慨的垂直空白(主要部分之间 128px),编辑/叙述优先的美学
- 语气: 平静、反思、权威。像个人回顾日记,而不是监控仪表板。
页面框架(页眉 + 页脚)
在 7 个部分之前,页面包含:
-
页眉: 左侧报告标题(Playfair Display,约 36px),下方是项目名称 + 日期范围,使用浅色元文本。右侧:等宽的文件计数(例如“223 次拒绝 · 71 天”)。通过底部边框与内容分隔。在第 1 节之前有慷慨的底部内边距。
-
页脚: 第 7 节之后。顶部边框,居中的斜体 Playfair Display 标语,总结语料库(例如“对 Plannotator 存档中 X 个被拒绝计划的分析。”)。
仪表板部分顺序(7 个部分)
报告遵循此确切部分顺序。每个部分建立在前一个部分的基础上——流程从“发生了什么”到“为什么”再到“该怎么做”:
-
数据中的故事 — 一段编辑叙述段落(Playfair Display 衬线,约 26px),用散文讲述头条发现。不是项目符号——一个真正的段落,读起来像文章的开头。旁边是一个 KPI 侧边栏,包含 3 个关键指标(最高拒绝百分比、总体修订率以及发现的独特拒绝类别数量)。在叙述中最引人注目的数字上使用琥珀色内联高亮。
-
计划被拒绝的原因 — 分类作为排名列表。每行:排名编号(等宽)、类别标签、一个细的 4px 进度条(第一项琥珀色-500,其余石板色-300)、百分比(等宽),对于顶部条目,在标签下方有一个真实的斜体引用。显示前 10 个类别或数据支持的数量(最少 5 个)。
-
期望如何演变 — 每个自然时间段一个卡片。每个卡片有:斜体的时间段名称、彩色大写主题短语(每个时间段不同颜色以显示进展)、描述段落以及底部的统计行(例如“X 次拒绝 · Y 个叙述请求”)。如果数据跨度少于 3 个不同的时间段,则使用 2 个卡片甚至一个带有内部进展说明的卡片。
-
什么有效 vs 什么无效 — 两个并排的卡片。左侧:绿色调(翡翠绿-50/50 背景,翡翠绿-100 边框),包含对此审阅者成功的计划特征。右侧:红色调(玫瑰红-50/50 背景,玫瑰红-100 边框),包含代理一直出错的地方。两者均来自 reduce 分析。使用带颜色的小圆点项目符号。每张卡片 5-8 项。
-
可操作的输出 — 诊断的回报。以 Playfair Display 叙述句开头,说明推导出了多少条提示指令以及它们估计能解决多大比例的拒绝(使用阶段 3 中计算的实际百分比,而不是通用数字)。然后是最具影响力的前 3 项改进,作为编号项,每个带有琥珀色编号、粗体标题和一行描述。此部分连接分析和后续的完整提示。
-
您最常用的短语 — 芯片网格(移动端 2 列,桌面端 3 列)。每个芯片:左侧等宽引用的短语,右侧频率计数。白色背景,石板色-200 边框,圆角 12px。显示 9-12 个最常出现的短语。这些应该是审阅者的实际词语——他们的语言指纹。
-
纠正性提示 — 深色面板(石板色-900 背景,白色文本,圆角 3xl,阴影-xl)。以 Playfair 介绍句开头,关于指令。然后是一个深色代码块(石板色-800/80 背景,琥珀色-200 等宽文本),包含阶段 3 中完整的编号提示指令。包含一个可用的复制到剪贴板按钮(包含 JS)。代码块下方:一个渐变发光卡片(靛蓝到紫色模糊光晕,后面是白色卡片),带有结束语,说明这些指令是个性化的——来自用户自己的反馈、自己的语言、自己的标准。
适配规则
- 如果用户的数据少于 3 个月,将演变部分减少为更少的卡片
- 如果大多数被拒绝的文件在
---下方缺少反馈(没有注释的裸拒绝),在叙述中注明——分析将较薄弱 - Claude Code 回退模式: 明确将报告来源标记为 Claude Code
ExitPlanMode拒绝原因。不要捏造仅 Plannotator 才有的字段,如注释计数或已批准计划的行数。有关 KPI 替代和页脚/来源指南,请参见回退参考。 - 如果出现的拒绝类别少于 5 个,将分类和模式部分合并为一个
- 如果数据集非常小(< 20 个文件),叙述应承认样本量有限,并将发现视为初步
- 提示指令的数量因用户而异——可能是 8 条或 20 条。不要强制恰好 17 条。让数据决定数量。
- 第 5 节中的前 3 项可操作项必须是覆盖最大比例拒绝的 3 项,而不是听起来最令人印象深刻的 3 项
关键规则
- 每个数字必须来自真实分析——没有捏造的数据
- 每个引用必须是来自真实文件的真实引用
- 分类百分比必须根据真实计数计算
- 提示指令必须追溯到实际的拒绝模式
- 提示块上的复制按钮必须有效(包含 JS)
生成后,在用户的浏览器中打开文件。
阶段 5:总结
告诉用户:
- 分析了多少个被拒绝的文件
- 如果是增量:自上次报告以来新增了多少个
- 发现的前 3 个拒绝模式
- 提示指令估计能解决多大比例的拒绝
- 单个最有影响力的提示改进
- 报告保存位置(包括版本号)
- 如果是增量:提醒用户早期发现在之前的报告中
Claude Code 回退模式: 根据回退参考调整总结——报告分析的人类拒绝原因和扫描的总 ExitPlanMode 尝试次数,而不是 Plannotator 文件计数。
阶段 6:改进钩子
在呈现总结后,询问用户是否要启用改进钩子——这将从报告第 7 节中获取纠正性提示指令,并将其写入一个文件,Plannotator 的 EnterPlanMode 钩子可以自动将其注入到每个未来的规划会话中。
“您想启用改进钩子吗?这将把纠正性提示指令保存到一个文件中,该文件会自动注入到所有未来的规划会话中——这样 Claude 在编写任何计划之前就能看到您的反馈模式。”
如果是:
钩子文件位于:
${PLANNOTATOR_DATA_DIR:-~/.plannotator}/hooks/compound/enterplanmode-improve-hook.txt
如果不存在,在数据目录内创建 hooks/compound/ 目录。
文件内容应为阶段 3 中的纠正性提示指令——与 HTML 报告第 7 节中出现的相同编号列表。将它们写为纯文本,每行一条指令,前面加上编号。没有 HTML,没有 markdown 围栏,没有前言——只有指令本身。钩子系统会按原样将此文件的内容注入到规划上下文中。
如果文件已存在:
读取现有文件并向用户提供选择:
“改进钩子已从之前的分析中存在。我可以:
- 替换 — 用新指令覆盖(旧指令将丢失)
- 合并 — 合并两者,去重重叠的指令,并保留每个指令的最佳版本
- 保留现有 — 保持当前钩子不变,跳过此步骤
您更喜欢哪个?”
- 替换: 用新指令覆盖文件。
- 合并: 读取现有指令,与新指令比较,并生成合并集。删除重复项(即使措辞不同但意图相同)。当两条指令覆盖同一模式时,保留更具体或更可操作的版本。按顺序重新编号最终列表。将合并结果写入文件。向用户显示更改内容(新增 N 条,删除 N 条冗余,保留 N 条现有)。
- 保留现有: 不执行任何操作,继续。
如果否: 完全跳过此阶段。
重要说明
- 数据源优先级: Plannotator 是首选路径。Claude Code 日志分析是给没有 Plannotator 存档的用户的次要路径。
- 研究完整性: 必须读取每个文件。此分析的价值来自完整性。抽样或跳过会削弱发现。
- 仅真实数据: 绝不捏造引用、百分比或模式。如果数据没有显示清晰的模式,请诚实说明,而不是编造一个。
- 让数据主导: 分类、模式和指令应从文件中实际存在的内容中涌现。不同的用户会有完全不同的拒绝模式。构建移动应用的用户与构建 API 的用户会有不同的反馈。不要假设模式会是什么。
- 代理并行化: 对于大型数据集,最大化并行代理以减少实际时间。瓶颈是最大的批次——拆分它。
- 结构化提取格式: 要求提取代理返回具有一致分隔符的结构化文本,以便 reduce 代理能够可靠地解析。
- 报告是工件: HTML 仪表板是用户保留的内容。它应该美观、诚实且有用。每个部分都应感觉像是专门为他们写的,因为它确实是。






