whynot-cli 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,257 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="assets/icon-dark.svg">
4
+ <img src="assets/icon-light.svg" alt="whynot" width="88">
5
+ </picture>
6
+ </p>
7
+
8
+ <h1 align="center">whynot</h1>
9
+
10
+ <p align="center">
11
+ <b>你的 agent 一直在重提你已经否决过的方案。</b><br>
12
+ 把它记一次。它会过期。agent 就不再提了。
13
+ </p>
14
+
15
+ <p align="center">
16
+ <a href="https://www.npmjs.com/package/whynot-cli"><img src="https://img.shields.io/npm/v/whynot-cli?style=flat-square&color=111111&label=npm" alt="npm"></a>
17
+ <img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="MIT">
18
+ <img src="https://img.shields.io/badge/node-%E2%89%A520-brightgreen?style=flat-square" alt="node 20+">
19
+ <img src="https://img.shields.io/badge/tests-29%20passing-brightgreen?style=flat-square" alt="29 tests passing">
20
+ <img src="https://img.shields.io/badge/dependencies-0-brightgreen?style=flat-square" alt="zero dependencies">
21
+ </p>
22
+
23
+ <p align="center">
24
+ <img src="https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey?style=flat-square" alt="platforms">
25
+ <img src="https://img.shields.io/badge/MCP-compatible-8A2BE2?style=flat-square" alt="MCP compatible">
26
+ <img src="https://img.shields.io/badge/Claude%20Code%20%C2%B7%20Codex%20%C2%B7%20Cursor%20%C2%B7%20Gemini%20CLI-supported-informational?style=flat-square" alt="agent support">
27
+ </p>
28
+
29
+ <p align="center">
30
+ <a href="README.md">English</a> · <a href="README.zh-CN.md">简体中文</a>
31
+ </p>
32
+
33
+ ---
34
+
35
+ <p align="center">
36
+ <a href="#problem">问题</a> ·
37
+ <a href="#install">安装</a> ·
38
+ <a href="#quick-start">快速开始</a> ·
39
+ <a href="#how-it-works">工作原理</a> ·
40
+ <a href="#evidence">证据</a> ·
41
+ <a href="#docs">文档</a> ·
42
+ <a href="#license">许可证</a>
43
+ </p>
44
+
45
+ ---
46
+
47
+ <a id="problem"></a>
48
+ ## 问题
49
+
50
+ 你试过用 Redis 存 session。一次区域故障时它读到 8 秒,于是你换成了 Postgres。
51
+
52
+ 三周后,一个新会话里,你的 agent 建议用 Redis。
53
+
54
+ 你又解释了一遍。一个月后你从 Claude Code 换到 Codex,第三次解释。半年后,你自己也记不清当初为什么否决 Redis 了——团队里其他人更不知道。
55
+
56
+ **代码记得住你选了什么。没有任何东西记得住你否决了什么。**
57
+
58
+ 记忆类工具记录的是「发生了什么」,那些在 commit、PR 和代码里本来就有。`whynot` 记录另一半:**你排除了哪些方案、为什么**,放在一个 agent 提议任何东西之前会读的文件里。
59
+
60
+ ---
61
+
62
+ <a id="install"></a>
63
+ ## 安装
64
+
65
+ ```bash
66
+ npx whynot-cli init
67
+ ```
68
+
69
+ 不需要全局安装,不用注册账号,没有遥测。只需要 Node 20+。
70
+
71
+ ---
72
+
73
+ <a id="quick-start"></a>
74
+ ## 快速开始
75
+
76
+ ### 1. 先看哪些规则永远不会过期
77
+
78
+ `audit` 是只读的。它扫描你现有的 `AGENTS.md`、`CLAUDE.md`、`.cursor/rules`,找出那些**用绝对语气、却没写任何条件**的规则——会被永久遵守的那些。
79
+
80
+ ```bash
81
+ npx whynot-cli audit
82
+ ```
83
+
84
+ ```
85
+ Scanned 2 agent config files:
86
+ AGENTS.md (last changed 412d ago)
87
+ CLAUDE.md (last changed 8d ago)
88
+
89
+ 3 rules look like permanent constraints:
90
+
91
+ AGENTS.md:3
92
+ "Never use TypeScript in this repo."
93
+ → absolute rule with no stated condition; unchanged for 412 days
94
+ ```
95
+
96
+ ### 2. 创建记录目录
97
+
98
+ ```bash
99
+ npx whynot-cli init
100
+ ```
101
+
102
+ 创建 `.decisions/`,并往 `.gitattributes` 写入 `*.md text eol=lf`。
103
+
104
+ ### 3. 记录一条否决
105
+
106
+ ```bash
107
+ npx whynot-cli add \
108
+ --title "session 不存 Redis" \
109
+ --why "us-east 故障时读延迟 8s,SLO 要求 p99 < 500ms" \
110
+ --type rejected \
111
+ --revisit "Redis 支持跨区域强一致时" \
112
+ --evidence pr:412 \
113
+ --tags infra,session
114
+ ```
115
+
116
+ ```markdown
117
+ ---
118
+ id: 0001
119
+ title: session 不存 Redis
120
+ type: rejected
121
+ status: live
122
+ created: 2026-09-21
123
+ expires_on: 2026-12-20
124
+ revisit_when: "Redis 支持跨区域强一致时"
125
+ evidence:
126
+ - "pr:412"
127
+ tags: [infra, session]
128
+ ---
129
+
130
+ ## 结论
131
+ 不能把 session 存 Redis。
132
+
133
+ ## 为什么
134
+ 试过 Redis + 单写区域。us-east 故障时读延迟飙到 8s,SLO 要求 p99 < 500ms。
135
+ ```
136
+
137
+ ### 4. 交给你的 agent
138
+
139
+ 加上 MCP server:
140
+
141
+ ```json
142
+ {
143
+ "mcpServers": {
144
+ "whynot": {
145
+ "command": "npx",
146
+ "args": ["-y", "whynot-cli", "mcp"]
147
+ }
148
+ }
149
+ }
150
+ ```
151
+
152
+ 然后把 [`AGENTS.snippet.zh-CN.md`](AGENTS.snippet.zh-CN.md) 里的那一段粘进你的 `AGENTS.md` 或 `CLAUDE.md`。MCP server 提供工具,这段指令才让 agent 真的去用。
153
+
154
+ > **MCP 不可用时,格式依然能用。** `.decisions/` 就是普通 Markdown,agent 可以直接读、直接 grep。这一条在真实 agent 测试里被观察到,不是假设。
155
+
156
+ ---
157
+
158
+ <a id="how-it-works"></a>
159
+ ## 工作原理
160
+
161
+ ### 每条记录都会过期
162
+
163
+ | 类型 | 默认有效期 |
164
+ |---|---|
165
+ | `rejected`(已否决) | 90 天 |
166
+ | `decision`(决策) | 180 天 |
167
+ | `constraint`(约束) | 365 天 |
168
+
169
+ 到期后,它**不再到达你的 agent**。不加注释、不加警告——直接不存在。`whynot stale` 会列出来,你决定续期还是归档。
170
+
171
+ 这是整个设计的核心。让 agent「对旧笔记保持怀疑」被实测证明没有用;**把它从视野里移走**才有用。
172
+
173
+ ### 三种记录
174
+
175
+ | 类型 | 用来记什么 |
176
+ |---|---|
177
+ | **`rejected`** | 试过并放弃的方案。**最值钱的一类**——仓库里没有别的东西记得它。 |
178
+ | `decision` | 在几个可行方案之间做的选择,附理由 |
179
+ | `constraint` | 项目必须满足的硬约束 |
180
+
181
+ ### 刻意做得很轻
182
+
183
+ - **Markdown 放在 git 里。** 能读、能 diff、能 review、能回滚。工具消失了,`grep` 依然能用。
184
+ - **不用向量库、不用 embedding、写入时不调模型。** 每一条都是失败模式:索引过期、写入成本、没人能审计的结果。
185
+ - **没有守护进程、没有遥测、没有托管服务。** 你对自己代码库的推理留在你自己的机器上。
186
+
187
+ ---
188
+
189
+ <a id="evidence"></a>
190
+ ## 证据
191
+
192
+ 六个实验,三个模型家族,多数条件 n=20。
193
+
194
+ | 问题 | 结果 |
195
+ |---|---|
196
+ | 决策的年龄重要吗? | **不重要。** 30 天和 7 年被遵循的比例完全一样(各 0/12)。过期后 → 12/12。 |
197
+ | 记录否决会改变结论吗? | **会。** 78–87 个百分点,p < 0.0001。 |
198
+ | 不相关的记录会扭曲无关工作吗? | **不会。** 0/30。 |
199
+ | 真实 agent 会跨会话使用它吗? | **会。** Codex 在 9/9 个会话里遵守了决策。 |
200
+
201
+ 安装之前,有两条需要知道:
202
+
203
+ - **约五分之一的回复抵抗了陈旧记录**——方式是攻击记录里写的原因。命名了**「条件」**的理由(「团队当时不会 TS」)会邀请复核;陈述了**「属性」**的理由(「这个项目变更频繁」)不会。
204
+ - **当真实代码在上下文里时,有些 agent 会直接从仓库推断答案**、无视记录。记录最有价值的地方,是代码表达不了的东西:**你否决掉的方案**。
205
+
206
+ 完整结果、方法和复现脚本:[`docs/findings.zh-CN.md`](docs/findings.zh-CN.md)。
207
+
208
+ ---
209
+
210
+ <a id="docs"></a>
211
+ ## 文档
212
+
213
+ | | |
214
+ |---|---|
215
+ | [设计](docs/design.zh-CN.md) | 为什么是这个形态 |
216
+ | [结论汇总](docs/findings.zh-CN.md) | 每个实验发现了什么、没发现什么 |
217
+ | [验证索引](docs/validation.zh-CN.md) | 详细写稿的入口 |
218
+ | [预注册](docs/preregistration.md) | 在数据之前定好的判据 |
219
+ | [贡献指南](CONTRIBUTING.md) | 四条不可协商的设计约束 |
220
+ | [AGENTS 片段](AGENTS.snippet.zh-CN.md) | 让 agent 真正用起来的那段指令 |
221
+
222
+ ---
223
+
224
+ ## 命令行
225
+
226
+ ```
227
+ whynot init 创建 .decisions/ 和 .gitattributes 规则
228
+ whynot add --title T --why W 记录一条
229
+ [--type rejected|decision|constraint]
230
+ [--revisit "条件"] 什么时候该重新考虑
231
+ [--ttl N] 多少天后过期
232
+ [--expires never] 显式设为永久
233
+ [--evidence pr:412] 可重复
234
+ [--tags infra,session]
235
+ whynot list [--all] 列出有效记录
236
+ whynot check "<查询>" 查某件事是不是已经定了
237
+ whynot stale 需要人决定的记录
238
+ whynot renew <id> [--days N] 续期
239
+ whynot retire <id> 归档(不删除)
240
+ whynot audit [--days N] 扫描 agent 配置文件(只读)
241
+ whynot doctor 校验记录
242
+ whynot mcp 运行 MCP server(stdio)
243
+ ```
244
+
245
+ ---
246
+
247
+ <a id="license"></a>
248
+ ## 许可证
249
+
250
+ MIT。没有账号、没有遥测、没有付费档、没有闭源二进制。
251
+ **没有任何东西要卖给你。**
252
+
253
+ ---
254
+
255
+ <p align="center">
256
+ <sub><a href="README.md">English</a> · <a href="https://github.com/Stakenshake/whynot">GitHub</a> · <a href="https://www.npmjs.com/package/whynot-cli">npm</a></sub>
257
+ </p>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" fill="none" role="img" aria-label="whynot">
2
+ <g stroke="#F5F5F5" stroke-width="7" stroke-linecap="round">
3
+ <path d="M20 60h30"/>
4
+ <path d="M50 60 84 32"/>
5
+ <path d="M50 60 84 88"/>
6
+ <path d="M90 26l14 14"/>
7
+ <path d="M104 26 90 40"/>
8
+ </g>
9
+ <circle cx="20" cy="60" r="8" fill="#F5F5F5"/>
10
+ <circle cx="92" cy="94" r="8" fill="#F5F5F5"/>
11
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" fill="none" role="img" aria-label="whynot">
2
+ <g stroke="#111111" stroke-width="7" stroke-linecap="round">
3
+ <path d="M20 60h30"/>
4
+ <path d="M50 60 84 32"/>
5
+ <path d="M50 60 84 88"/>
6
+ <path d="M90 26l14 14"/>
7
+ <path d="M104 26 90 40"/>
8
+ </g>
9
+ <circle cx="20" cy="60" r="8" fill="#111111"/>
10
+ <circle cx="92" cy="94" r="8" fill="#111111"/>
11
+ </svg>
package/bin/whynot.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { main } from '../src/cli.js';
3
+
4
+ main();
package/docs/design.md ADDED
@@ -0,0 +1,139 @@
1
+ # Design
2
+
3
+ Why the tool looks like this.
4
+
5
+ ## The problem
6
+
7
+ A coding agent has no memory of last week. Every session starts from nothing.
8
+ That is mostly fine: the code is the state, and the agent can read it. What it
9
+ cannot read is **why you rejected an approach**.
10
+
11
+ That knowledge has three properties that make it hard:
12
+
13
+ - It does not exist in the repository. It exists in someone's head.
14
+ - It decays. Six months later, the person remembers "we tried something" but
15
+ not what broke.
16
+ - It is expensive to rediscover. The agent will happily spend tokens walking
17
+ the same dead end again.
18
+
19
+ ## The finding that shaped the design
20
+
21
+ We recorded a 2019 decision — "do not use TypeScript, the team does not know
22
+ it" — and asked two model families to choose a stack for a brand-new 2026
23
+ service. Every response followed the seven-year-old note. Adding a warning to
24
+ the prompt ("this is old, be skeptical") did not fix it. Making the entry
25
+ expire did.
26
+
27
+ The full numbers are in [validation.md](validation.md).
28
+
29
+ The conclusion: **an agent cannot be relied on to weigh a stale instruction
30
+ correctly.** So the design does not ask it to. An expired entry is not shown to
31
+ the agent at all.
32
+
33
+ This one decision explains most of the rest of the design.
34
+
35
+ ## Four decisions
36
+
37
+ ### 1. Data is Markdown in git
38
+
39
+ Everything else follows from this.
40
+
41
+ - A human can read and edit it without the tool.
42
+ - `git diff` gives review for free.
43
+ - `git revert` gives an undo for free.
44
+ - If the project is abandoned, the data is still usable with `grep`.
45
+
46
+ Most tools in this space store decisions in a database or a vector index. When
47
+ those projects die, users lose the data along with the tool. This project is
48
+ designed so that cannot happen.
49
+
50
+ ### 2. Expiry is the default
51
+
52
+ Every entry carries an expiry date. `rejected` entries last 90 days, `decision`
53
+ 180, `constraint` 365. When it lapses, the entry stops reaching the agent.
54
+
55
+ An expired entry is not deleted. `whynot stale` surfaces it, and a human either
56
+ renews it or retires it. Both are explicit actions.
57
+
58
+ `expires_on: never` exists for genuinely permanent constraints, but it must be
59
+ written deliberately. Permanence should be a decision, not a default.
60
+
61
+ ### 3. No embeddings, no model calls on write
62
+
63
+ Retrieval is deliberately simple: case-insensitive keyword matching over titles,
64
+ tags, and bodies, scored by how many query terms hit.
65
+
66
+ Two reasons:
67
+
68
+ - **Auditability.** When an entry appears in the agent's context, it is obvious
69
+ why: the words matched. With embeddings, nobody can explain it.
70
+ - **Cost and failure modes.** Vector indexing goes stale. LLM extraction is
71
+ expensive and is the main source of corrupted memories in the tools that use
72
+ it. Both are avoidable here, so they are avoided.
73
+
74
+ The trade-off is real: keyword matching misses paraphrases. That is why
75
+ `decisions_check` with no query returns a compact index of everything live, so
76
+ the agent can see the full list cheaply before narrowing down.
77
+
78
+ ### 4. The format works without the tool
79
+
80
+ The agent gets `decisions_check` through MCP. If MCP is unavailable, it can
81
+ still read `.decisions/` directly — that is just Markdown.
82
+
83
+ This was not a theoretical property. In the Codex integration test, the MCP
84
+ call was blocked by an approval policy, and the agent fell back to reading the
85
+ files and still respected the decision.
86
+
87
+ ## Form factor: four layers, not one
88
+
89
+ A common mistake in this category is picking one form and forcing everything
90
+ through it. Each concern here belongs to a different layer:
91
+
92
+ | Layer | Form | Why it has to be this |
93
+ |---|---|---|
94
+ | Data | `.decisions/*.md` in git | Works with zero tooling. The durable asset. |
95
+ | Behaviour | A block in `AGENTS.md` | Making an agent *proactively record* a rejection is an instruction, not an API. |
96
+ | Capability | MCP server | Pull-based, structured, works across agents. |
97
+ | Human loop | CLI | Renewing and retiring are human decisions. |
98
+ | Distribution | npm and agent plugins | Zero-install; meets people where they already are. |
99
+ | **Not** | Hosted API | Decisions about a codebase are the most sensitive artifact in the repo. Hosting them defeats the purpose. |
100
+
101
+ ## Cross-platform
102
+
103
+ The project targets Windows, macOS, and Linux, because the failure modes are
104
+ different on each.
105
+
106
+ - **Line endings.** `init` writes `*.md text eol=lf` to `.gitattributes`.
107
+ Without it, Windows checkouts write CRLF and every diff shows the whole file.
108
+ - **Filenames.** Windows forbids `\ / : * ? " < > |`, and Windows and macOS are
109
+ case-insensitive. Filenames are slugged to `[a-z0-9]` plus CJK, which
110
+ eliminates a class of "works on Linux" bugs.
111
+ - **No background process.** Windows file watching is unreliable and needs
112
+ native dependencies. The tool is invoked, never resident.
113
+ - **No git hooks.** Cross-platform shell in hooks is a minefield. Not used.
114
+
115
+ ## Deliberately not built
116
+
117
+ - Vector search or embeddings.
118
+ - Any model call in the write path.
119
+ - A daemon or file watcher.
120
+ - A web UI.
121
+ - Automatic detection of rejections (a hook is possible later, but it is not
122
+ required for the core loop).
123
+ - Team sync. `git` already does this.
124
+ - Multi-repo aggregation.
125
+
126
+ Each one is a real feature someone has asked for. Each one also makes the tool
127
+ heavier, and this category has a graveyard full of heavier tools.
128
+
129
+ ## Open questions
130
+
131
+ - **Does the repeated-mistake rate actually drop in real use?** The experiments
132
+ measure single-turn behaviour. The claim that matters is longitudinal and has
133
+ not been measured yet.
134
+ - **How often does expiry lose knowledge people still need?** The trade is
135
+ deliberate, but the ratio is unknown. `whynot stale` is where that shows up.
136
+ - **Does this survive being used by a team?** The design assumes one person
137
+ curating. With five people, who renews what?
138
+ - **Is 90 days right for a rejection?** It is a guess. Different codebases move
139
+ at different speeds.
@@ -0,0 +1,102 @@
1
+ # 设计说明
2
+
3
+ 这个工具为什么长这样。
4
+
5
+ ## 问题
6
+
7
+ 编码 agent 对上周发生的事没有记忆。每次会话都从零开始。这本身问题不大——代码就是状态,agent 可以自己读。但它读不到的是:**你为什么否决了某个方案。**
8
+
9
+ 这类知识有三个麻烦的性质:
10
+
11
+ - 它不在仓库里,在某个人脑子里。
12
+ - 它会腐烂。半年后,那个人只记得「当时好像试过」,不记得具体哪里崩了。
13
+ - 重新发现它的代价很高。agent 会毫不心疼地再走一遍那条死路。
14
+
15
+ ## 决定了整个设计的那个发现
16
+
17
+ 我们记录了一条 2019 年的决策——「不要用 TypeScript,团队没人会」——然后让两个模型家族给一个 **2026 年的全新服务**做技术选型。**每一次回复都遵循了那条七年前的笔记。** 在提示词里加一句「这条很旧,请保持怀疑」没有修好。让条目过期,才修好。
18
+
19
+ 完整数字见 [validation.zh-CN.md](validation.zh-CN.md)。
20
+
21
+ 结论是:**不能指望 agent 正确地权衡一条陈旧指令。** 所以设计上干脆不要求它权衡——**过期条目根本不出现在 agent 的视野里。**
22
+
23
+ 这一条决定了后面大部分设计。
24
+
25
+ ## 四个决定
26
+
27
+ ### 1. 数据是 git 里的 Markdown
28
+
29
+ 其他一切都由此而来。
30
+
31
+ - 人不用工具也能读、能改。
32
+ - `git diff` 免费提供 review。
33
+ - `git revert` 免费提供撤销。
34
+ - 就算项目被放弃,数据依然能用 `grep` 检索。
35
+
36
+ 这个领域里大多数工具把决策存进数据库或向量索引。那些项目死掉时,用户会连数据一起丢。这个项目从设计上就不允许这种事发生。
37
+
38
+ ### 2. 默认过期
39
+
40
+ 每条记录都带一个到期日。否决类 90 天,决策类 180 天,约束类 365 天。到期后,条目不再到达 agent。
41
+
42
+ 过期条目**不会被删除**。`whynot stale` 会把它列出来,由人决定续期还是归档。两者都是显式动作。
43
+
44
+ `expires_on: never` 是为真正永久的约束准备的,但必须刻意写出来。**永久应该是一个决定,不是一个默认值。**
45
+
46
+ ### 3. 不用 embedding,写入时不调模型
47
+
48
+ 检索刻意做得很简单:对标题、标签、正文做大小写不敏感的关键词匹配,按命中的查询词数量排序。
49
+
50
+ 两个理由:
51
+
52
+ - **可审计。** 当一条记录出现在 agent 的上下文里,原因一目了然:词对上了。用 embedding 的话,没人解释得清它为什么在那儿。
53
+ - **成本与失败模式。** 向量索引会过期。用 LLM 抽取记忆很贵,而且正是这类工具里记忆被污染的主要来源。这两样在这里都可以避免,所以就不做。
54
+
55
+ 代价是真实的:关键词匹配会漏掉改写的说法。所以 `decisions_check` 在不带查询条件时会返回一个紧凑的索引,让 agent 先廉价地看到全貌,再往下缩小范围。
56
+
57
+ ### 4. 没有工具时,格式依然可用
58
+
59
+ agent 通过 MCP 调用 `decisions_check`。如果 MCP 不可用,它仍然可以直接读 `.decisions/`——那不过是 Markdown。
60
+
61
+ 这不是理论上的性质。在 Codex 集成测试里,MCP 调用被审批策略拦住了,agent 自动降级去读文件,并且**依然遵守了那条决策**。
62
+
63
+ ## 形态:四层,不是一个
64
+
65
+ 这个品类里一个常见的错误是选一种形态,然后把所有事都塞进去。这里的每件事属于不同的层:
66
+
67
+ | 层 | 形态 | 为什么必须是这个 |
68
+ |---|---|---|
69
+ | 数据 | git 里的 `.decisions/*.md` | 零工具依赖也能用。这是唯一不会死的资产。 |
70
+ | 行为 | `AGENTS.md` 里的一段指令 | 让 agent **主动记录**否决,是指令问题,不是 API 能力问题。 |
71
+ | 能力 | MCP server | 拉取式、结构化、跨 agent 通用。 |
72
+ | 人的回路 | CLI | 续期和归档是人的决定。 |
73
+ | 分发 | npm + agent 插件 | 零安装,在用户已经在的地方出现。 |
74
+ | **不是** | 托管 API | 关于代码库的决策是仓库里最敏感的东西。托管它就等于毁掉整个前提。 |
75
+
76
+ ## 跨平台
77
+
78
+ 目标平台是 Windows、macOS、Linux,因为三者的坑不一样。
79
+
80
+ - **换行符。** `init` 会往 `.gitattributes` 写 `*.md text eol=lf`。不写的话,Windows 上会写入 CRLF,每次 diff 都显示整个文件被改。
81
+ - **文件名。** Windows 禁止 `\ / : * ? " < > |`,而且 Windows 和 macOS 大小写不敏感。文件名会被 slug 成 `[a-z0-9]` 加中日韩字符,从根上消除一整类「Linux 上好的、换个系统就崩」的问题。
82
+ - **没有常驻进程。** Windows 的文件监听不可靠且需要原生依赖。工具只被调用,不常驻。
83
+ - **不用 git hooks。** 跨平台的 shell 在 hook 里是雷区。所以不用。
84
+
85
+ ## 刻意不做的东西
86
+
87
+ - 向量检索 / embedding
88
+ - 写入路径上的任何模型调用
89
+ - 守护进程或文件监听
90
+ - Web UI
91
+ - 自动检测否决(以后可以用 hook,但核心闭环不依赖它)
92
+ - 团队同步。`git` 本身就是。
93
+ - 多仓库聚合
94
+
95
+ 每一条都是真的有人要过的功能。每一条也都会让工具更重,而这个品类的坟场里全是更重的工具。
96
+
97
+ ## 还没有答案的问题
98
+
99
+ - **真实使用中,重复犯错率真的会降吗?** 实验测的是单轮行为。真正重要的主张是长期的,而那个还没测。
100
+ - **过期多久会丢掉人还需要的信息?** 这是一个刻意的取舍,但比例未知。`whynot stale` 是它显现的地方。
101
+ - **团队用它撑得住吗?** 设计假设是一个人维护。五个人时,谁负责续期?
102
+ - **否决类 90 天合适吗?** 这是猜的。不同代码库的节奏不一样。