# Open Loops

> 当用户希望找回长对话中没有被看见、确认或明确取舍的信息点时使用。包括四类情况：用户提了但 AI 没答、AI 提了但用户没接住、AI 替用户做了选择，以及 AI 本该提问却自行决定。用户说「对账」 「建清单」「哪些没闭环」「open loops」，或抱怨对话跑偏、旧问题消失、AI 替自己做主时触发。 长项目进行到一半才开始审计，也属于正常入口。用户明确启用后，在该项目或任务中持续逐轮运行， 直到用户明确暂停或停止，不要求每轮重新点名。不要用于单轮编号问答、普通任务进度追踪，或用户 已经明确看见但暂缓执行的事项。仅检查、调试、修改或发布 Open Loops 本身的轮次属于维护通道： 可以使用本 skill 排障，但不得写进业务项目的原文存档或未闭环清单。

- Skill: `haorantang97/open-loops` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add haorantang97/open-loops`
- Raw SKILL.md: https://api.skillmd.com/api/skills/haorantang97/open-loops/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: PolyForm-Noncommercial-1.0.0
- Author: haorantang97 (https://skillmd.com/u/haorantang97)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/haorantang97/open-loops

---


# Open Loops

## Quick Start

1. 检查 `docs/open-loops.md` 和 `docs/open-loops-source.md`。不存在就先初始化。
2. 把启用状态写入项目的 `AGENTS.md` 或 `CLAUDE.md`；启用后持续运行，直到用户明确停止。
3. 每轮先判断是否为 Open Loops 维护通道；纯维护轮次不进入业务存档，也不触发业务审查。
4. 对业务轮次，逐字追加上一轮用户消息、上一轮助手回复和本轮用户消息。
5. 派一个没参与主对话的子 agent，只传两个文件路径，并原样使用后文的「审查员指令」。
6. 审查员必须先核销旧条目，再检查新增掉点；没有新增就输出 `NONE`，但卡片轮次仍推进。
7. 如果已有长对话但存档为空，先走「首次调用：全量复盘」，再进入逐轮稳态。

初始化项目文件：

```bash
mkdir -p docs
printf '# Open Loops\n\n## 未闭环 0 · 更新于第 0 轮\n\n---\n\n## 已闭环\n\n## 已主动废弃\n' > docs/open-loops.md
printf '# 原文存档\n\n> 逐字，只增不改。\n\n<!-- ↑ 已核对到此 ↑ -->\n' > docs/open-loops-source.md
```

## 装到哪

**把这个文件原样放到下面任一位置，文件名保持 `SKILL.md`，父目录名必须叫 `open-loops`：**

| 工具 | 全局 | 项目内 |
|---|---|---|
| Claude Code | `~/.claude/skills/open-loops/SKILL.md` | `.claude/skills/open-loops/SKILL.md` |
| Codex CLI | `~/.codex/skills/open-loops/SKILL.md` | `.codex/skills/open-loops/SKILL.md` |
| OpenClaw | `~/.agents/skills/open-loops/SKILL.md` | `<workspace>/skills/open-loops/SKILL.md` |
| Cowork / claude.ai | 设置 → Capabilities → 上传 | - |

一行搞定（Claude Code 全局）：

```bash
mkdir -p ~/.claude/skills/open-loops && mv SKILL.md ~/.claude/skills/open-loops/
```

**不认 skill 格式的 agent**（网页版 ChatGPT / Gemini / 各种 IDE 助手）：
把本文件从「常驻规则」那一段开始整段粘进对话，或者粘进它的 system prompt / 自定义指令。
装不了 skill 不影响它跑：**这套东西的实体只是两个 markdown 文件加一段规则**，
skill 格式只是让它自动加载而已。

---

## 它治什么

用户一条消息提了三件事：前端交互、UI、后端 bug。AI 回了一大段，前端分析得特别细，
UI 给了两个方案，**后端那个 bug 一个字没提，也没说「这条我跳过了」**。

**漏的那一刻，屏幕上什么都没多出来。而一段对话里，只有产生摩擦的东西才会被追踪。**

### 四种掉法，第二种是主力

| # | 情况 |
|---|---|
| 1 | 用户提了，AI 没答 |
| 2 | **AI 答了，用户没接住** ← **最高频** |
| 3 | AI 替用户做了选择 |
| 4 | AI 该问没问 |

**第二种为什么是主力**：现在模型漏答已经少了。用户问 abcde，多半都答了：
**但他只对 abcd 下了下一步指令，e 就没了。找出那个 e，是主要工作。**

---

## ⚠️ 做不好会比没有更糟

清单由模型维护，模型会漏。

**一个不存在的清单不会给用户虚假保证；一个存在但漏项的清单会。**
用户会开始信任它，于是不再重读自己的原话：静默遗漏就升级成了「盖了章的遗漏」。

必须告诉用户：**偶尔自己翻一下原文存档。** 这一条工具替不了。

---

## 边界：只管「有没有看到」，不管「做完没有」

**这条划错，整个东西会长成一个长任务监视器。**

- 用户**没看到**的点 → 这个 skill 的活
- 用户**看到了**、但决定以后再做 → **知识库/项目卡片的活，不是这里**

**用户一旦接住并下了指令，这条就出表。** 至于他做不做、什么时候做，不归它管。

---

## 两个文件

- `docs/open-loops.md`：清单
- `docs/open-loops-source.md`：业务主线原文存档，逐字，只增不改；维护通道不写入

初始化：

```bash
mkdir -p docs
printf '# Open Loops\n\n## 未闭环 0 · 更新于第 0 轮\n\n---\n\n## 已闭环\n\n## 已主动废弃\n' > docs/open-loops.md
printf '# 原文存档\n\n> 逐字，只增不改。\n\n<!-- ↑ 已核对到此 ↑ -->\n' > docs/open-loops-source.md
```

两个都进 git。

---

## 常驻规则（粘进 AGENTS.md 或 CLAUDE.md）

```markdown
## Open Loops

- **状态：启用。** 从用户明确启用的那一轮开始，每个后续业务轮次都运行，直到用户明确说暂停或停止；
  不依赖用户再次提到 skill。首次启用时告诉用户：无新增默认静默，但清单中的更新轮次仍会推进。
- **维护通道**：如果一轮主要是在询问、调试、修改或发布 Open Loops 本身，不把该轮或相邻维护回复
  写入业务项目的 `docs/open-loops-source.md`，也不让它改变业务清单。维护结束后从下一条业务消息续接。
- **每轮开始**：把「上一轮往返 + 用户本轮消息」**逐字**追加进 `docs/open-loops-source.md`，
  然后按下面那一档派生一个子 agent 跑 open-loops 的审查员指令。
  **只给它文件路径，不要转述内容**：我的转述已经是有损的。
- **子 agent 模型档位：未配置。** 如果项目常驻规则尚未记录模型档位，就先别跑：**先列出当前
  平台可用的模型、按强度排序并给出推荐**（这项工作是分类抽取，稳态用最便宜的够用档；首次全量
  复盘可以上一档），**然后问用户选哪个**。用户选完后，把选择写进这条项目常驻规则；不要修改
  已安装的 `SKILL.md`。之后不再问。若平台不能选择模型，明确说明并使用平台默认值。
- **它只找四种掉出去的点**：①用户提了我没答 ②**我说了用户没接住（主力）**
  ③我替用户做了选择 ④我该问没问。**登记要同时过两道判据：不看会不会有东西被默认定下来 ＋
  不专门找看不看得见。**
- **用户已经接住并下了指令的，一律出表。** 他看到了就够了，做不做不归这张表管。
- **先核销、后新增**：审查员每轮必须先检查当前全部未闭环项是否已被上一轮助手实质回答，
  修正陈旧理由，再寻找新掉点；禁止让“之前没答”在后来已经回答后继续挂着。
- **默认静默**。只报本轮新增的，一条一行。全表罗列、历史积压、无变化一律不出现。
- **能问必须问。** 登记不是询问的替代。
- **禁止按轮数自动归档，禁止自行标废弃。** 往「结束」方向的变更不能静默发生。
- 对账时逐条读 `docs/open-loops.md` 核对，**禁止靠回忆对话**。结尾只放清单状态，
  不放「我建议下一步」。
```

Claude 系：`ln -sf AGENTS.md CLAUDE.md`

---

## 审查员指令（核心 · 每轮派子 agent 时原样使用）

```
你是「漏检员」。你没参与过这段对话，这是刻意的：你看不到那几十轮上下文，
所以不会被其中被反复展开的少数几个话题带偏。

## 读什么

1. docs/open-loops-source.md：业务原文存档，读最后两段：
   · 上一轮：用户说了什么 + 助手答了什么
   · 本轮：用户刚说了什么
2. docs/open-loops.md：当前清单

自己去读。不要依赖任何人给你的转述。

## 第零步：先核销旧条目

逐条检查当前「未闭环」。只用上一轮助手原文判断，不凭记忆：

- 用户原本要的是解释、调研、方案或答案，后来已经得到实质回答 → 立即移入「已闭环」，
  不要求用户再回复“收到”；纯信息交付不会因沉默而形成默认决定。
- 条目涉及助手已经代选并实际采用的方案、权限或范围 → 用户未接住前继续挂。
- 回答只完成了原要求的一部分 → 继续挂，但把理由改成当前真实缺口，禁止保留“完全没答”的旧理由。

核销不是自动废弃：不得因为时间过去、轮数增加或用户换话题而关闭。

## 第一步：找出新掉出去的信息点

| # | 什么情况 | 时序 |
|---|---|---|
| 1 | 用户提了，助手上一轮没实质回答 | 滞后一轮 |
| 2 | **助手上一轮说了，用户本轮没接住** ← 主力 | **零滞后** |
| 3 | 助手替用户做了选择 | 滞后一轮 |
| 4 | 助手该问却没问，自己定了 | 滞后一轮 |

第 2 种是主力：现在模型漏答已经少了，大部分遗忘发生在用户侧：
助手答了 abcde，用户只对 abcd 下了指令，e 就这么没了。**找出那个 e。**

## ⚠️ 两道判据，必须同时过

1. **用户如果永远不看这条，会不会有什么被默认定下来？**
2. **用户不专门去找的话，看得见吗？**

**「会被定下来」+「看不见」→ 登记。** 否则一律不登记。

- 助手解释了个原理、陈述了个事实 → 不看也没什么被定下来 → **不登记**
- 助手提了「你这方案并发上去会有性能问题」，用户没接 → 不接＝默认接受 → **登记**
- 助手写了 15 分钟的稿而不是 10 分钟 → 写在标题上一眼可见 → **不登记**
- 助手把追踪对象整个换掉了 → 得拿原需求对比才发现 → **登记**

**判据不是看语气。**「我建议用 A」说完停下来等 = 不登记；
说完直接按 A 往下做了 = **登记**：礼貌的口吻会让用户以为还有选择权，
其实默认值已经生效了。

## 绝对不登记

**用户已经接住并下达了下一步指令的。** 他看到了，你的活就完了。
至于他接下来做不做、什么时候做，不归你管。

还有：纯解释、纯事实、能一句话答完且答完就完的（门槛是「跨轮存在」）。

## ⚠️ 只判状态，不判质量

**唯一标准：在回应里指得出处理这个点的那一段吗？**

指得出、有实质内容 → 闭环。
指得出、但那句话删掉用户不损失信息 → 未闭环（一笔带过）。
完全指不出 → 未闭环。

**明令禁止判断**：答得好不好、够不够深、篇幅比重对不对、应不应该多讲。

理由：你一旦开始判质量，就会把「我觉得这里该多讲」包装成「这条没闭环」。
清单被你的口味污染，用户收到一堆假警报，然后把整套东西关掉。
**会误报的审查员比没有审查员更糟。**

**重构问题不算降级。** 用户问「多长合适」，助手答「33 分钟，但更要紧的是这些不该塞一期」：
处理了原需求就是闭环。但如果重构改变了范围或形态，另记一条代决。

## 登记怎么写

**一条一行，带编号，抄原话不要改写，不要合并。**
合并是最隐蔽的降级：五件事变三件，没人会发现少了两件。

格式是「一句话：为什么还挂着」：

    3. 数据库选型：我选了 PostgreSQL（替代项 MySQL），等你确认

**只有「未闭环」一个状态。** 区别全部写在后半句人话里，不要再拆状态词。

- **代决**必须写得出一个会导致不同结果的**替代项**，写不出说明是执行细节，不登记。
- **岔路**必须写成一句用户**可以直接回答的问句**，写不出问句说明还没想清楚，先别登记。

## 出表

四条路：助手后来实质补答了纯信息请求 / 用户处理了 / 用户明说废弃（**抄录原话**）/
用户说转知识库卡片。代决类条目仍必须等用户接住，不能用“助手后来解释过”代替确认。

**禁止按轮数自动归档。** 往「结束」方向的变更不能静默发生，
否则就是你替用户做了废弃决定。

用户说了类似废弃的话但不确定（「那个先不管」可能是「这周先不管」），
**不要直接移走**，在后半句写「你说过「先不管」，确认废弃吗？」，等他下轮确认。

注意区分：「可以忘掉了」是明确废弃；「先搁置」不是：搁置继续挂着。

## 格式约束（硬的）

**不要改动文件结构、区块标题、编号方式。不要"优化排版"。**
格式漂移是静默的：下游会悄悄读不到，而没有人会发现。

## 输出两部分，收件人不同

**第一部分**：先完成旧条目核销，再写入新增项并更新 docs/open-loops.md 顶栏
`## 未闭环 N · 更新于第 N 轮`。即使没有新增，业务轮次编号也要推进，作为常驻运行证据。

**第二部分**：回报主 agent（会出现在对话里，所以极度克制）。

**默认输出 NONE。只报本轮新增的**，每条一行：

    ⚠ 上一轮我说的「<摘录>」你这轮没接 - 已记为 #N
    ⚠ 你提的「<摘录>」我上一轮没答 - 已记为 #N
    ⚠ 我选了 X（替代项 Y），你没表过态 - 已记为 #N

以下一律**不要**放进第二部分（只写进文件）：全表罗列 · 历史积压 · 已闭环 ·
状态没变的条目 · 「本轮无变化」这类占位话：没有就输出 NONE。

**为什么这么克制**：常态也有摩擦，摩擦就会贬值。第三十轮那行字如果和前二十九行长得一样，
会被一起跳过：等真出事那次也失效了。**摩擦要省着花在异常上。**
```

---

## 清单长什么样

```markdown
# Open Loops · <项目名>

## 未闭环 5 · 更新于第 27 轮

1. 缓存策略：我第 12 轮答过，你一直没表态
2. 配色要不要换：我一直没答
3. 数据库选型：我选了 PostgreSQL（替代项 MySQL），等你确认
4. 登录报错：需你先给个测试账号
5. 暗色模式：你说过「先不管」，确认废弃吗？

---

## 已闭环
（一行摘要）

## 已主动废弃
| # | 信息点 | 用户原话 | 第几轮 |
```

**打开就能用，不用往下翻，能直接回「1、3 处理，5 废弃」。**

---

## 首次调用：全量复盘（主路径，不是异常）

**大多数人是聊了几十轮、发现东西丢了才想起来调用。「有前文」是正常状态。**

```
存档为空 → retrofit：自动派子 agent 全量复盘前文，不需要用户额外说
存档非空 → 稳态：逐轮追加
```

**硬规则：主 agent 不得手工转录对话内容。** 三条路，按优先级：

1. **脚本**从原始会话记录机械提取
2. **子 agent 自己读**源文件
3. **明说做不到**，只覆盖当前上下文并标注范围

**没有第四条。手抄一遍正是「传指针不传内容」要防的那个有损环节。**

### 找原始记录

各平台位置不同，**先探测，不要硬编码**。

Claude Code（已验证）：`~/.claude/projects/*/[0-9a-f]*.jsonl`
通用探测：`find ~ -name "*.jsonl" -newermt "-2 day" -size +50k | grep -iE "session|transcript|projects"`

**探测不到就走第 3 条，不要猜路径、不要手抄。**

### 提取脚本

```python
import json
out, turn = [], 0
for line in open(TRANSCRIPT):
    try: d = json.loads(line)
    except: continue
    if d.get('type') not in ('user','assistant'): continue
    c = d.get('message', {}).get('content')
    txt = c if isinstance(c, str) else "\n".join(
        b.get('text','') for b in c if isinstance(b, dict) and b.get('type')=='text'
    ) if isinstance(c, list) else ''
    if not txt.strip() or 'system-reminder' in txt[:200]: continue
    if d['type'] == 'user':
        turn += 1; out.append(f"\n\n===== 第 {turn} 轮 · 用户 =====\n{txt}")
    else:
        out.append(f"\n----- 第 {turn} 轮 · 助手 -----\n{txt}")
open('docs/open-loops-source.md','w').write("".join(out))
```

### 首次要主动说的两个偏差

**一、批量闭环告警会误报。** 首次会一次性判定几十条已闭环：形状和「草率闭环」一致，
但性质不同，如实说明是首次建账所致。

**二、时序是推算的。** 「第 N 轮」是数出来的，补录时不如实时可靠。

首次给完整报告；之后回到默认静默。

---

## 对账

**打开清单，从第一行走到最后一行逐条核对。**

**禁止**问自己「我们还有什么没做」再从记忆里捞：那是从被少数话题占满的上下文里回忆，
**会漏掉的正好是同一批东西**。

另读原文存档中「已核对到此」标记之后的新增段，问「这里面还有什么没进表」。

报告**带行号**，**结尾只放清单状态，不放「我建议下一步」**：
下一步该由用户从清单里挑，否则又把优先级排序外包出去了。

---

## 模型：先问用户，别自己定

它干的是**分类 + 抽取**，判据全写死在指令里，没有创作、没有开放推理。**小模型的主场。**

但用哪一档**不是你替用户定的**：它每轮都跑，是笔持续开销。

**第一次跑之前，四步：**

1. **列出当前平台可用的模型。** 不要写死型号名，各家不一样，还老变。
2. **按强度排一下。**
3. **给一条推荐**：稳态每轮用**最便宜的够用档**；首次全量复盘可以**上一档**：
   一次性的事，错了会污染地基。
4. **问用户选哪个。**

用户选完写进上面常驻规则那行槽位，**之后不再问**。选不了就说一声。

⚠️ **降档必须配一次校准**：拿同一段用高一档再跑，差 3 条以上、
或便宜档**滑进了质量判断**（冒出「这里讲浅了」）→ 升一档。
**弱模型最典型的失效不是漏报，是守不住「只判状态不判质量」那条边界。**

---

## 什么时候**不需要**这个工具

实测过：**单轮 + 编号清单**的场景（一条消息列 7 条编号诉求，一轮答完），
七条全部闭环，静默降级基本不发生。**编号本身就是最强的防漏机制。**

价值只在**跨轮累积**时出现。一次性的多问清单不用装。

---

## 验证它真的在跑

**装完必须做一次，否则可能装了个哑巴还以为被保护着。**

1. 发一条含三件事的消息
2. 确认 AI 三条都答了
3. **下一轮只对其中两条下指令，第三条一个字不提**
4. **看它当轮报不报第三条**

报了就是活的，没报就是摆设。**这一步是零滞后的**，第 3 步一发第 4 步当轮就该出现。

反向验证：三条都下指令 → 应该**什么都不报**；接住之后**不该再看到它**。

再做两项回归：先让助手漏答并登记，下一轮补上实质答案，确认旧条目自动闭环；插入一轮只讨论
Open Loops 自身的维护消息，确认它既不进入业务原文，也不改变业务清单。

---

## Common Mistakes

**让主 agent 靠记忆自审。**
主 agent 已经被长上下文影响，很难看到自己遗漏的点。应派独立子 agent，只让它读取原文存档和清单。

**把对话概括后再交给审查员。**
概括会先丢一次信息，审查员只能审到被筛过的版本。只传文件路径，让审查员读取逐字存档。

**把「已看见但暂缓执行」继续挂在表里。**
这会把信息审计变成任务管理。用户一旦接住并下达指令，该条就出表。

**没有新增也输出状态提示。**
每轮都出现「无变化」会耗尽用户注意力。没有新增时输出 `NONE`，不要制造占位摩擦。

**静默关闭或自动归档。**
按轮数关闭、把「先搁置」当成废弃，都会替用户做决定。只有用户明确处理、废弃或转入知识库时才能出表。

**只查新增，不核销旧账。**
这会让“上一轮没答”在答案已经补交后仍然挂着。每轮必须先核销全部旧条目，再检测新增。

**把启用当成单轮触发。**
Skill 的自动触发不保证跨轮继承；必须把“持续启用直到明确停止”写进项目常驻规则。

**把 Skill 维护讨论写进业务账。**
询问状态卡、排查误报、修改或发布本 Skill 都走维护通道，不污染业务项目上下文。

---

## 已知弱点

**入口靠主 agent 逐字复制**：是复制不是概括，但漏抄了它自己也不会知道。

**子 agent 也会漏**：它强在无上下文污染、任务窄、每次新起，
这三条**显著降低**概率，不能**消除**。

**放弃了机械校验**：全靠语义判断，覆盖率换掉了可验证性。这是取舍，不是纯改进。

**常驻不是置顶 UI 卡片**：它表示每个业务轮次都执行。没有宿主产品支持时，只能用清单的更新轮次
证明仍在运行，不能假装生成了一个永久悬浮组件。

**「回到自己的清单再决定下一步」是用户的习惯，工具替不了。**

---

## 无子 agent 能力时的降级

主 agent 自己做一次「干净重读」：只打开存档最后两段和清单，**不回忆对话**，只据此判断。

**必须明确告诉用户已降级**：审计员的独立性是地基，主 agent 自审 = 让被审计者填审计表，
而「我漏了什么」恰恰是被审计者看不见的东西。**降级后价值大打折扣，不是等价替代。**

一个悄悄降级还装作没事的工具，就是它自己要治的病。

