---
name: agent-self-maintenance
description: 用五个「会失败」的小机制让 AI 编码助手长期维护自己的记忆——日记闸门、开局对账、事实核查、自我观察、自检收据。适用于任何有 journal/ 与自检脚本的仓库；含各机制的判据与边界（目录缺失时说什么、数据为什么不能随机制搬走）。
---

# Agent 自我维护：五个会失败的小机制

## 为什么需要它们

一个会长期工作的 agent 最容易发生的不是「做错」，而是**「没人问」**：

- 日记停在某一天，没人发现；
- 自检红了三天，没人知道；
- 事实库写着「上游已迁移」，而实际没有；
- 「她说的」和「我量的」被混成一句结论。

这五件事的共同点：**不做也不会报错**。所以每个机制都必须有一个「会失败」的形态，
并且要能回答「谁在跑它」。

## 五个机制

### 1. 日记闸门（journal gate）

判据（两条，都从本 session 自己的事件日志读）：

- **做过事**：本 session 里出现过 `git commit`；
- **没记事**：`journal/<当日>.md` 不存在或未被本 session 修改。

两条同时成立 → 收尾时提醒一次。**是门，不是自觉。**

边界：只在「有 journal 惯例的仓库」启用；没配置就安静——不要每个 session 都念
「你没写日记」，那会变成噪音，而噪音会被忽略。

### 2. 开局对账（journal catchup）

闸门有一个结构性缺口：**它只在 session 里活着**。没有 session 的工作（终端里改的、
定时任务动的）它看不见。所以开局要读一次账：

| 输入 | 要回答的问题 |
|---|---|
| 自检收据 | 上次自检是什么时候？红了哪几项？ |
| 日记 | 上次日记是哪天？之后有没有提交？ |
| 事实库 | 有没有过期的事实？（每条事实带日期） |

**三种状态不合并**：ok / red / stale。「没跑过」必须说出来。

### 3. 事实核查（facts check）

事实库里的每一条都是**活标本**：带日期、带证据、带探针。

- **探针**：一条能重新量出该事实的命令；
- **第三种状态**：`无法核验`（探针跑不了）——它既不是通过也不是失败；
- **抄来的与量到的分开记**：`source: upstream-doc` vs `source: measured`。

### 4. 自我观察（inquiry）

每一条观察回答三个问题：

1. 这是**她说的**（引用 + 时间）？
2. 还是**我量的**（命令 + 输出）？
3. 还是**不确定**（明确标注）？

条目必须带日期与证据。**不要在一句话里混用两种来源。**

### 5. 自检收据（selfcheck receipt）

自检脚本每跑一次写一份收据（时刻、rev、失败项）。判据有五种状态：

| 状态 | 含义 |
|---|---|
| `ok` | 刚跑过且全绿 |
| `red` | 跑过但有失败项 |
| `stale` | 太久没跑（阈值由仓库定） |
| `missing` | 没有收据 |
| `unreadable` | 收据在但读不出来 |

**只有 `ok` 是安静的**；其余四种都要在开局说出来。

## 边界：机制搬走，数据留在原地

| 东西 | 归属 |
|---|---|
| 五个机制的**判据与形态** | 技能 / 预设（可移植） |
| 事实条目、观察条目、预算阈值、自检阈值 | **仓库自己的数据**（不随机制搬） |
| 收据文件（`state/selfcheck.json`） | 仓库自己的产物（不进版本库） |

**为什么这条重要**：机制是「怎么判断」，数据是「判断什么」。把数据随机制一起下放，
等于替使用者断言了他们的事实——而那些事实第二天就会过期。

## 最小落地

不要求任何特定 harness。三个可移植形态：

1. **钩子**（harness 支持时）：session 结束 / 开始时触发；
2. **收尾命令**：`make check` 或 `scripts/maintain.sh` 里串一遍；
3. **纯人工 + 收据**：至少让「没跑」留下痕迹。

判据只有一条：**它必须有个会失败的地方，并且有人或机器在跑它。**
