driftseal 1.3.2 → 2.0.0
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.
- package/README.md +223 -322
- package/README.zh-CN.md +199 -287
- package/bin/driftseal-mcp.js +156 -62
- package/bin/driftseal.js +1971 -352
- package/index.js +3 -0
- package/package.json +4 -3
- package/skills/use-driftseal/SKILL.md +19 -13
package/README.zh-CN.md
CHANGED
|
@@ -1,365 +1,277 @@
|
|
|
1
1
|
# DriftSeal
|
|
2
2
|
|
|
3
|
-
> **Seal the
|
|
3
|
+
> **Seal the outcome. Stop the drift.**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
在 agent 动手改代码之前,DriftSeal 先记下这一轮究竟要完成什么、准备如何证明完成;工作结束后,再记录实际发生了什么。这个轻量契约不会因为 context loss、范围悄悄膨胀,或者一句过于乐观的“完成了”而消失。
|
|
5
|
+
DriftSeal 是一套跟随 repo 保存的协议与工具,用来让 coding agent 始终围绕一个
|
|
6
|
+
完整的交付 outcome 工作。它要求在持久改动开始前记录 outcome,允许以 append-only
|
|
7
|
+
方式补充同一 outcome 的后续步骤,把验证结果绑定到累计 contract,并只为确实需要
|
|
8
|
+
长期保留理由的选择建立 MADR。
|
|
10
9
|
|
|
11
10
|
```text
|
|
12
|
-
|
|
11
|
+
开启 outcome → 扩展同一 outcome → 验证累计 contract → 关闭
|
|
13
12
|
```
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
一个 worktree 只持有一个 open outcome。Git 记录最终落地了什么;DriftSeal 记录这轮
|
|
15
|
+
工作想交付什么、如何证明完成,以及长期 decision 背后的理由。
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## v2 的变化
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
| --- | --- |
|
|
21
|
-
| 任务做到一半,范围悄悄扩大 | 当前轮次始终只有一个清晰可见的 intent |
|
|
22
|
-
| 没有可靠证据,也可以宣布“完成” | 实现前就先声明 verification |
|
|
23
|
-
| Context compaction 后忘记最初目标 | `status` 和 `log` 能准确找回 intent 与历史 |
|
|
24
|
-
| 同一场架构争论被不同 agent 反复重演 | 克制使用的 [MADR](https://adr.github.io/madr/) 记录保留真正重要的理由 |
|
|
25
|
-
| 并发或中断写入让状态变得可疑 | Lock、schema check、atomic write 与 recovery 让异常可检测、可恢复 |
|
|
19
|
+
DriftSeal v2 从“按步骤记录 intent”改为“按交付记录 outcome”。
|
|
26
20
|
|
|
27
|
-
|
|
21
|
+
- 所有状态归到同一个 seal root:`.seal/outcomes/events.jsonl` 与 `.seal/madr/`。
|
|
22
|
+
- `DRIFTSEAL_HOME` 覆盖整个 v2 `.seal` root。从 v1 继承的值仍指向 intent-log
|
|
23
|
+
目录;migration 时需要显式传入旧位置,之后再 unset 或替换这个变量。
|
|
24
|
+
- `driftseal extend` 可以向当前 outcome 追加步骤、acceptance、verifier 或 decision link。
|
|
25
|
+
- 每次 extend 都会改变 contract hash,并让之前的 verification 与 MADR reconciliation 失效。
|
|
26
|
+
- event 使用 `logVersion: 2`、`schemaVersion: 1`。
|
|
27
|
+
- `AGENTS.md` 的新协议版本从 `2.0` 开始,兼容改进依次使用 `2.1`、`2.2`。
|
|
28
|
+
- CLI、Node API、MCP tool 与 resource 全部使用 outcome 命名;v1 名称和路径不会作为
|
|
29
|
+
runtime alias 保留。
|
|
28
30
|
|
|
29
|
-
##
|
|
31
|
+
## 安装
|
|
32
|
+
|
|
33
|
+
DriftSeal 需要 Node.js 18 或更高版本。
|
|
30
34
|
|
|
31
35
|
```sh
|
|
32
36
|
npm install --global driftseal
|
|
33
|
-
|
|
34
|
-
driftseal init
|
|
37
|
+
driftseal --version
|
|
35
38
|
```
|
|
36
39
|
|
|
37
|
-
|
|
38
|
-
并配置 local git merge driver。重复运行不会产生副本。用 `--lang zh-CN`(或其他
|
|
39
|
-
[BCP 47](https://www.rfc-editor.org/rfc/rfc5646.html) 标签)声明 agent 写入
|
|
40
|
-
intent / decision 正文时应使用的语言,默认是 `en`。命令名、flag、status token、
|
|
41
|
-
id 以及 MADR 小节标题仍保持英文。再次运行不带 `--lang` 的 `init` 会保留已声明
|
|
42
|
-
的语言并升级协议。DriftSeal 需要 Node.js 18+。
|
|
43
|
-
|
|
44
|
-
从当前 checkout 本地开发时:
|
|
40
|
+
在源码 checkout 中使用:
|
|
45
41
|
|
|
46
42
|
```sh
|
|
47
|
-
npm
|
|
43
|
+
npm install
|
|
44
|
+
node bin/driftseal.js --version
|
|
48
45
|
```
|
|
49
46
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
默认组合是 `AGENTS.md` + 配套 skill + CLI:
|
|
53
|
-
|
|
54
|
-
- `driftseal init` 写入的 `AGENTS.md` 是唯一的 policy 来源。
|
|
55
|
-
- `skills/use-driftseal` 是不绑定特定 agent runtime 的轻量发现与恢复指南。
|
|
56
|
-
- `driftseal` CLI 是默认执行入口。
|
|
57
|
-
|
|
58
|
-
为指定平台安装 package 内置的 skill。默认使用项目级 scope:
|
|
47
|
+
让 repo 接入协议:
|
|
59
48
|
|
|
60
49
|
```sh
|
|
61
|
-
driftseal
|
|
62
|
-
driftseal skill install --target kimi-code --scope global
|
|
50
|
+
driftseal init
|
|
63
51
|
```
|
|
64
52
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
| `kimi-code` | `.kimi-code/skills/use-driftseal` | `~/.kimi-code/skills/use-driftseal` |
|
|
69
|
-
| `opencode` | `.opencode/skills/use-driftseal` | `~/.config/opencode/skills/use-driftseal` |
|
|
70
|
-
| `claude-code` | `.claude/skills/use-driftseal` | `~/.claude/skills/use-driftseal` |
|
|
71
|
-
| `cursor` | `.cursor/skills/use-driftseal` | `~/.cursor/skills/use-driftseal` |
|
|
53
|
+
`init` 会写入或升级 `AGENTS.md` 中的 managed blocks,添加 outcome log 的 merge
|
|
54
|
+
attribute,并配置本地 Git merge driver。Git config 不会随 clone 传播,因此新 clone
|
|
55
|
+
需要再执行一次 `init`。
|
|
72
56
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
MCP 与 lifecycle hook 都是可选适配层;只有确实存在 host 限制或提醒需求时
|
|
77
|
-
才启用,不要把它们叠成额外的 policy 层。
|
|
57
|
+
`driftseal init --lang <BCP-47-tag>` 用来指定 outcome 与 MADR 正文的语言。
|
|
58
|
+
`--local-log` 会让 `.seal/` 保持本地、不被跟踪;DriftSeal 只报告当前 tracked 状态,
|
|
59
|
+
不会替你修改 `.gitignore` 或 Git index。
|
|
78
60
|
|
|
79
|
-
##
|
|
61
|
+
## 基本工作流
|
|
80
62
|
|
|
81
|
-
|
|
82
|
-
intent 与 decision 工作流提供结构化 tools,并与 CLI 复用同一套锁、WAL、
|
|
83
|
-
atomic write、schema 和 recovery 实现。server 不会启动 `driftseal` 子进程,
|
|
84
|
-
也不需要解析 CLI 输出。
|
|
85
|
-
|
|
86
|
-
启动时把 server 固定到一个 repository:
|
|
63
|
+
在修改持久项目内容前,先开启完整的交付 outcome:
|
|
87
64
|
|
|
88
65
|
```sh
|
|
89
|
-
driftseal
|
|
66
|
+
driftseal begin "Ship account recovery" \
|
|
67
|
+
--accept "expired links are rejected" \
|
|
68
|
+
--accept "a valid link resets the password" \
|
|
69
|
+
--verify "npm test"
|
|
90
70
|
```
|
|
91
71
|
|
|
92
|
-
|
|
72
|
+
如果下一步仍属于同一个交付目标,就把它追加到当前 outcome:
|
|
93
73
|
|
|
94
74
|
```sh
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
driftseal mcp install --target opencode
|
|
99
|
-
driftseal mcp install --target claude-code
|
|
100
|
-
driftseal mcp install --target cursor
|
|
75
|
+
driftseal extend "Document recovery-link expiry" \
|
|
76
|
+
--accept "the expiry behavior is documented" \
|
|
77
|
+
--verify "npm test && npm run docs:check"
|
|
101
78
|
```
|
|
102
79
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
| Target | 项目级配置 | 全局配置 |
|
|
108
|
-
| --- | --- | --- |
|
|
109
|
-
| `codex` | `.codex/config.toml` | `~/.codex/config.toml` |
|
|
110
|
-
| `kimi-code` | `.kimi-code/mcp.json` | `~/.kimi-code/mcp.json` 或 `$KIMI_CODE_HOME/mcp.json` |
|
|
111
|
-
| `opencode` | `opencode.json` | `~/.config/opencode/opencode.json` |
|
|
112
|
-
| `claude-code` | `.mcp.json` | `~/.claude.json` |
|
|
113
|
-
| `cursor` | `.cursor/mcp.json` | `~/.cursor/mcp.json` |
|
|
80
|
+
新增 acceptance 时,必须提供一个能证明完整累计 contract 的替代 verifier。没有新增
|
|
81
|
+
acceptance 的 extend 可以沿用原 verifier,也可以替换它。任何 extend 都会让之前的
|
|
82
|
+
machine evidence 失效。如果交付目标本身变了,应诚实关闭当前 outcome,再开启新的。
|
|
114
83
|
|
|
115
|
-
|
|
116
|
-
的用户级配置:
|
|
84
|
+
完成前依次执行:
|
|
117
85
|
|
|
118
86
|
```sh
|
|
119
|
-
driftseal
|
|
87
|
+
driftseal status
|
|
88
|
+
driftseal verify
|
|
89
|
+
driftseal end --status completed --note "Shipped recovery with expiry documentation."
|
|
120
90
|
```
|
|
121
91
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
root 只能在启动时配置,不是 tool input。MCP 模式也会忽略继承到进程中的
|
|
127
|
-
`DRIFTSEAL_HOME` 和 `DRIFTSEAL_DECISION_HOME` override,因此 tool call 不能把
|
|
128
|
-
写入重定向到所选 repository 之外。
|
|
92
|
+
acceptance-bound outcome 只有在最新 verification 成功后才能关闭为 `completed`。证据
|
|
93
|
+
同时绑定 contract hash 与 Git-visible workspace fingerprint。若 verification command
|
|
94
|
+
只来自 tracked log、没有匹配的本地 provenance,检查后还必须显式使用
|
|
95
|
+
`--allow-tracked-command`。
|
|
129
96
|
|
|
130
|
-
|
|
97
|
+
发生 context loss 或 handoff 后,先重新锚定:
|
|
131
98
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
| `driftseal_absorb` | 修复 merge 撞号,或吸收另一条 worktree 日志并重编号冲突 ID。 |
|
|
137
|
-
| `driftseal_reclaim`, `driftseal_unreclaim` | 用 append-only 标记隐藏已无意义的已关闭记录,或将其恢复。 |
|
|
138
|
-
| `driftseal_decision_list`, `driftseal_decision_show` | 查找并读取 MADR record。 |
|
|
139
|
-
| `driftseal_decision_add`, `driftseal_decision_update` | 克制地增加 decision,并 reconcile 已关联的 decision。 |
|
|
140
|
-
| `driftseal://intent/current` | 以 JSON resource 读取当前 intent。 |
|
|
141
|
-
| `driftseal://intents/recent` | 以 JSON resource 读取最近十条 intent。 |
|
|
142
|
-
| `driftseal://decisions` | 以 JSON resource 读取 decision catalog。 |
|
|
99
|
+
```sh
|
|
100
|
+
driftseal status
|
|
101
|
+
driftseal log --last 3
|
|
102
|
+
```
|
|
143
103
|
|
|
144
|
-
|
|
145
|
-
放弃策略,以及 dry-run 模式。传入的路径只作为只读来源;修复后的内容仍只会写入
|
|
146
|
-
server 启动时固定的 repository。Git merge driver 形式仍是 CLI 专用的底层命令。
|
|
104
|
+
## 哪些工作需要 outcome
|
|
147
105
|
|
|
148
|
-
|
|
149
|
-
|
|
106
|
+
准备长期留在项目中的代码、配置、文档、依赖及同类文件改动需要 outcome。Git 操作、
|
|
107
|
+
检查命令、临时辅助工作,以及不会把持久内容写进项目的外部状态变化都不需要。
|
|
150
108
|
|
|
151
|
-
|
|
109
|
+
作用域属于 worktree,而不是某一个 agent process。同一 worktree 内的 agent 与
|
|
110
|
+
subagent 重新锚定并继续匹配的 open outcome;不同 worktree 各自持有 outcome。
|
|
152
111
|
|
|
153
|
-
|
|
154
|
-
注入一条简短的 DriftSeal 提醒,并在回答完毕时(`Stop`)显示警告。提醒是
|
|
155
|
-
建议性的——它提示是否需要开启 intent、是否还有未关闭的 intent 需要验证并
|
|
156
|
-
`driftseal end`;它不会强制模型再跑一轮,并且在还没有 intent log 的
|
|
157
|
-
repository 中保持沉默。
|
|
112
|
+
## Decision 与 MADR
|
|
158
113
|
|
|
159
|
-
|
|
114
|
+
只有当 outcome log 与 Git 无法还原重要上下文时才建立 MADR,例如值得以后重访的
|
|
115
|
+
rejected/deferred 路径、长期且难回退的选择理由,或 deprecated/superseded decision。
|
|
160
116
|
|
|
161
117
|
```sh
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
118
|
+
driftseal decision add "Expire recovery links after one hour" \
|
|
119
|
+
--context "Recovery links are security-sensitive bearer tokens." \
|
|
120
|
+
--outcome "Use a one-hour lifetime and reject older links." \
|
|
121
|
+
--driver "Limit token exposure" \
|
|
122
|
+
--option "No expiry" \
|
|
123
|
+
--option "One-hour expiry" \
|
|
124
|
+
--consequence "Users must request another link after expiry."
|
|
166
125
|
```
|
|
167
126
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
| `kimi-code` | 不支持 | `~/.kimi-code/config.toml` 或 `$KIMI_CODE_HOME/config.toml` |
|
|
171
|
-
| `claude-code` | `.claude/settings.json` | `~/.claude/settings.json` |
|
|
172
|
-
| `codex` | `.codex/hooks.json` | `~/.codex/hooks.json` |
|
|
173
|
-
|
|
174
|
-
与 `mcp install` 一样,hook 安装器支持 `--scope global`、
|
|
175
|
-
`--root <repository>` 和 `--force`,重复安装是幂等的,并保留无关的配置项。
|
|
176
|
-
Kimi Code 只在全局 `config.toml` 中记录 hook,因此该 target 必须指定
|
|
177
|
-
`--scope global`。Claude Code 的 prompt 提醒使用
|
|
178
|
-
`hookSpecificOutput.additionalContext`,`Stop` 提醒则使用只显示在 UI 中的
|
|
179
|
-
`systemMessage`,不会造成 continuation loop。Codex 只安装 prompt hook,
|
|
180
|
-
因为它的 `Stop` 事件没有建议性上下文通道。Hook 命令会从当前目录开始向上
|
|
181
|
-
查找 intent log。OpenCode 和 Cursor 目前还没有可用的 hook 入口。
|
|
182
|
-
|
|
183
|
-
## 一轮标准工作流
|
|
184
|
-
|
|
185
|
-
进行非 Git 改动前,先声明这轮工作的目标:
|
|
127
|
+
通过 `begin` 或 `extend` 的 `--decision <id>` 关联已有 MADR。outcome 关闭为
|
|
128
|
+
`completed` 或 `partial` 前,必须 reconcile 每一条关联记录:
|
|
186
129
|
|
|
187
130
|
```sh
|
|
188
|
-
driftseal
|
|
189
|
-
--accept "the sixth login attempt within one minute receives HTTP 429" \
|
|
190
|
-
--verify "npm test test/rate-limit.test.js"
|
|
131
|
+
driftseal decision update 1 --status accepted --note "Confirmed by the final implementation."
|
|
191
132
|
```
|
|
192
133
|
|
|
193
|
-
|
|
194
|
-
|
|
134
|
+
## 命令速查
|
|
135
|
+
|
|
136
|
+
| 命令 | 用途 |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `driftseal begin "<outcome>" [--accept "..."] [--verify "..."] [--decision id] [--force]` | 开启一个完整 outcome。 |
|
|
139
|
+
| `driftseal extend "<addition>" [--accept "..."] [--verify "..."] [--decision id]` | 向同一 outcome 追加内容,并让旧 verification 失效。 |
|
|
140
|
+
| `driftseal verify [--allow-tracked-command]` | 执行累计 verifier 并绑定证据。 |
|
|
141
|
+
| `driftseal end [id] [-s status] [-n note] [-r verify-result]` | 诚实关闭 outcome。 |
|
|
142
|
+
| `driftseal status` | 查看进行中的 outcome。 |
|
|
143
|
+
| `driftseal log [--last N] [--all]` | 查看 outcome 历史。 |
|
|
144
|
+
| `driftseal reclaim [id ...] --reason "..." [--force]` | 通过 append-only marker 隐藏无意义的已关闭记录。 |
|
|
145
|
+
| `driftseal unreclaim <id> --reason "..."` | 恢复 reclaimed record。 |
|
|
146
|
+
| `driftseal absorb [other-events.jsonl] [--decisions dir] [--abandon-theirs\|--abandon-ours]` | 合并另一条 lineage 并处理撞号。 |
|
|
147
|
+
| `driftseal decision add\|update\|list\|show` | 管理 MADR。 |
|
|
148
|
+
| `driftseal migrate v1-to-v2 inspect --json [migration paths]` | 规范化 v1 状态,供模型分组。 |
|
|
149
|
+
| `driftseal migrate v1-to-v2 apply --plan <file> [migration paths]` | 校验分组计划,并在 v1 旁边创建 v2 seal。 |
|
|
150
|
+
| `driftseal migrate v1-to-v2 check [migration paths]` | 校验 migration 结果并报告 review/deletion gate。 |
|
|
151
|
+
| `driftseal init [--lang tag] [--local-log]` | 安装或升级 repo 协议。 |
|
|
152
|
+
|
|
153
|
+
完整语法以及 skill、MCP、hook 的安装 target 请查看 `driftseal help`。
|
|
154
|
+
|
|
155
|
+
## 从 v1 migration
|
|
156
|
+
|
|
157
|
+
把按步骤记录的 intent 合并为真正交付的 outcome 需要语义判断,因此 migration 特意
|
|
158
|
+
采用 model-assisted 流程。
|
|
159
|
+
|
|
160
|
+
如果发现尚未 migration 的 v1 intent log 或 MADR 目录,普通 v2 repo 命令会 fail
|
|
161
|
+
closed,避免悄悄创建一条与 v1 历史无关的 `.seal` lineage。只有 MADR、没有 intent
|
|
162
|
+
log 的 v1 repo 也可以直接 migration,不必先创建空 log。
|
|
163
|
+
|
|
164
|
+
1. 先关闭所有 v1 intent。parked v1 intent 会挡住 migration;升级 CLI 之后用
|
|
165
|
+
`driftseal end`(例如 `--status abandoned`)关掉它,再跑 `inspect`。先合并或冻结
|
|
166
|
+
仍会改 `.intent-log` 的分支;`absorb --git` 会保留 v1 log 合并的两侧,而不是丢掉
|
|
167
|
+
theirs。
|
|
168
|
+
2. 读取规范化后的源数据:
|
|
169
|
+
|
|
170
|
+
```sh
|
|
171
|
+
driftseal migrate v1-to-v2 inspect --json > /tmp/driftseal-inspection.json
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
3. 让模型生成 `driftseal-v1-to-v2-plan` JSON。所有可见 v1 record 必须按原顺序组成
|
|
175
|
+
完整 partition。只有已经在 v1 中 reclaimed 的记录可以排除,而且每项都要给出理由。
|
|
176
|
+
如果没有剩余的可见记录,`groups` 可以为空;MADR 仍会照常 migration。
|
|
177
|
+
4. 用户审阅 outcome 分组后,应用认可的 plan:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
driftseal migrate v1-to-v2 apply --plan /tmp/driftseal-plan.json
|
|
181
|
+
driftseal migrate v1-to-v2 check
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`apply` 会为 source 计算 fingerprint,校验 partition 与 staged v2 log,逐字节复制
|
|
185
|
+
所有 v1 MADR,并记录文件名、大小与 hash manifest,使 v1 删除后 `check` 仍能验证
|
|
186
|
+
完整性。后续 MADR 内容只有在最新的有效 v2 reconciliation 已记录其当前 hash 时才会被接受。
|
|
187
|
+
`apply` 只会在 `.intent-log/`、`.decision-log/` 旁边新建 `.seal/`,绝不删除 v1 数据。
|
|
188
|
+
用户审阅并明确认可后,再手动移除旧路径。`check` 在这些路径仍被 git 跟踪时打印
|
|
189
|
+
`git rm`,在 `--local-log` 这类未跟踪布局下打印 `rm -rf`。随后执行 `check` 会报告
|
|
190
|
+
migration 已完成。
|
|
191
|
+
|
|
192
|
+
如果 v1 使用自定义存储,inspect 与 apply 都要明确给出 source 和 destination。
|
|
193
|
+
`DRIFTSEAL_DECISION_HOME` 只作为 v1 的 MADR source 默认值和 fail-closed 检测来源,
|
|
194
|
+
v2 运行期会忽略它。migration marker 会保存这些路径的规范 identity,之后 `check` 可以从 destination 找回
|
|
195
|
+
source。source 与 destination 不能互相包含,尤其不能把从 v1 继承的
|
|
196
|
+
`DRIFTSEAL_HOME` 同时当成 v2 destination:
|
|
195
197
|
|
|
196
198
|
```sh
|
|
197
|
-
driftseal
|
|
199
|
+
driftseal migrate v1-to-v2 inspect --json \
|
|
200
|
+
--source-log /path/to/v1-intents/events.jsonl \
|
|
201
|
+
--source-decisions /path/to/v1-decisions \
|
|
202
|
+
--destination /path/to/repository/.seal
|
|
203
|
+
driftseal migrate v1-to-v2 apply --plan /tmp/driftseal-plan.json \
|
|
204
|
+
--source-log /path/to/v1-intents/events.jsonl \
|
|
205
|
+
--source-decisions /path/to/v1-decisions \
|
|
206
|
+
--destination /path/to/repository/.seal
|
|
207
|
+
driftseal migrate v1-to-v2 check \
|
|
208
|
+
--destination /path/to/repository/.seal
|
|
198
209
|
```
|
|
199
210
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
`DRIFTSEAL_HOME` 则在 intent log 之外保存一个很小的本地标记。这些本地创建的
|
|
205
|
-
intent 可以直接验证。如果 open intent 只有 log 记录、没有匹配的本地 provenance,
|
|
206
|
-
DriftSeal 就无法确认是谁选择了其中的命令。此时它会先把命令输出到 stderr 并拒绝
|
|
207
|
-
执行;只有检查并信任该命令后,才能显式运行
|
|
208
|
-
`driftseal verify --allow-tracked-command`。Programmatic API 和 MCP tool 中对应的显式
|
|
209
|
-
开关是 `allowTrackedCommand`。intent 关闭时,本地 provenance 会被清理;如果它提前
|
|
210
|
-
丢失,DriftSeal 会按安全方向处理,仍要求显式 opt in。非 Git marker 还会绑定本地
|
|
211
|
-
log 文件的 identity,因此把 marker 和 log 一起复制到别处也不会转移信任。
|
|
212
|
-
|
|
213
|
-
验证事件会记录 exit status、耗时、输出摘要及字节数、Git HEAD,以及当前所有
|
|
214
|
-
tracked 和未被 ignore 的 untracked 文件的内容指纹(intent event log 除外)。
|
|
215
|
-
验证后只要这些内容发生变化,成功证据就会过期,必须重新运行;否则 DriftSeal
|
|
216
|
-
会拒绝把 intent 关闭为 `completed`。命令输出会先写入临时 spool 文件,而不是
|
|
217
|
-
受固定大小的内存 buffer 限制;命令退出后再回放并删除。因此 DriftSeal 不再限制
|
|
218
|
-
输出大小,但实际容量仍受可用磁盘空间约束。被 ignore 的文件不在指纹范围内。
|
|
219
|
-
如果当前目录不是 Git worktree,指纹不可用;此时 gate 只能证明记录到的 exit
|
|
220
|
-
status,无法发现之后发生的内容变化。
|
|
221
|
-
|
|
222
|
-
这只能证明预先声明的命令在记录的内容上通过,不能证明 acceptance criterion
|
|
223
|
-
或测试本身足够可靠。为兼容旧记录,没有 `--accept` 的 intent 仍沿用手动验证流程。
|
|
224
|
-
如果验证器也由同一个 agent 编写、结果带有主观判断,或改动风险较高,应再使用
|
|
225
|
-
受保护的 CI、独立 review 或人工确认。
|
|
226
|
-
|
|
227
|
-
最后记录实际结果:
|
|
211
|
+
apply 后应 unset v1 的 `DRIFTSEAL_HOME`,或让它指向新的 seal root。Node API 提供
|
|
212
|
+
`sourceLog`、`sourceDecisions`、`destination`;MCP migration tools 可指定自定义 v1
|
|
213
|
+
source,但 destination 固定为 server 所属 repo 的 `.seal`,因此普通 MCP workflow
|
|
214
|
+
tools 可以立刻看到 migration 后的状态。
|
|
228
215
|
|
|
229
|
-
|
|
230
|
-
driftseal end \
|
|
231
|
-
--status completed \
|
|
232
|
-
--note "Added the limiter and covered the failure path" \
|
|
233
|
-
--verify-result "4 tests pass"
|
|
234
|
-
```
|
|
216
|
+
## Git 与 merge
|
|
235
217
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
——比如从 commit range 重新生成的 patch 文件、可以重跑的临时 harness——也不需要
|
|
242
|
-
intent;会被提交且无法重建的内容改动(比如编辑 `.gitignore`)则需要。编译、跑测试
|
|
243
|
-
等单步构建或检查同样不需要 intent;除此之外的非 Git 内容改动,都要开启新一轮。
|
|
244
|
-
|
|
245
|
-
## 命令速览
|
|
246
|
-
|
|
247
|
-
| Command | 用途 |
|
|
248
|
-
| --- | --- |
|
|
249
|
-
| `driftseal begin "<intent>" [--accept "<outcome>"] [-v "<command>"] [--decision id] [--force]` | 开启一轮工作。可重复使用 `--accept` 声明可观察的完成条件;一旦声明,就必须同时提供验证命令。 |
|
|
250
|
-
| `driftseal verify [--allow-tracked-command]` | 执行 acceptance-bound intent 预先声明的命令,并把机器证据绑定到当前 Git 可见的工作区内容;没有匹配本地 provenance 的命令必须显式 opt in。 |
|
|
251
|
-
| `driftseal end [id] [-s status] [-n note] [-r verify-result]` | 诚实地关闭 intent。 |
|
|
252
|
-
| `driftseal status` | 查看当前进行中的 intent。 |
|
|
253
|
-
| `driftseal log [-n N] [--all]` | 查看 intent 历史(`--all` 包含已回收的记录)。 |
|
|
254
|
-
| `driftseal reclaim [id ...] --reason "..." [--older-than days] [--force] [--dry-run]` | 用 append-only 标记隐藏已无意义的已关闭记录。 |
|
|
255
|
-
| `driftseal unreclaim <id> --reason "..."` | 把已回收的记录恢复到可见历史中。 |
|
|
256
|
-
| `driftseal absorb [other-events.jsonl] [--decisions dir] [--abandon-theirs \| --abandon-ours] [--dry-run]` | 合并另一条 worktree 的日志,并给撞号的 intent / decision id 重新编号。 |
|
|
257
|
-
| `driftseal absorb --git <base> <ours> <theirs>` | `.intent-log/events.jsonl` 的 git merge driver。 |
|
|
258
|
-
| `driftseal decision add "<title>" -c "..." -o "..."` | 写入编号化的 MADR decision。 |
|
|
259
|
-
| `driftseal decision update <id> [-s status] -n "..."` | 在当前 intent 中 reconcile 已关联的 decision。 |
|
|
260
|
-
| `driftseal decision list [-s status] [--last N \| --count]` | 列出或统计 decision records,也可按 status 筛选。 |
|
|
261
|
-
| `driftseal decision show <id>` | 查看单条 decision record。 |
|
|
262
|
-
| `driftseal skill install --target TARGET [--scope project\|global] [--root path] [--force]` | 为 Codex、Kimi Code、OpenCode、Claude Code 或 Cursor 安装内置 skill。 |
|
|
263
|
-
| `driftseal mcp install --target TARGET [--scope project\|global] [--root path] [--force]` | 把固定到 repository 的 MCP server 安装到 Codex、Kimi Code、OpenCode、Claude Code 或 Cursor。 |
|
|
264
|
-
| `driftseal hook install --target TARGET [--scope project\|global] [--root path] [--force]` | 把建议性的 lifecycle 提醒安装到 Kimi Code、Claude Code 或 Codex。 |
|
|
265
|
-
| `driftseal hook prompt\|stop [--format plain\|claude-code]` | 输出 lifecycle hook 注入的提醒;绝不阻断。 |
|
|
266
|
-
| `driftseal init [--lang <tag>] [--local-log]` | 把接入协议写入 `AGENTS.md`,并配置 git merge driver。`--lang` 设置 intent / decision log 的语言(BCP 47,默认 `en`)。`--local-log` 让日志保持本地、不入库,不随代码提交;如果日志已被 git 跟踪,init 会打印警告和处理建议,但不会改动 index 或 `.gitignore`。 |
|
|
267
|
-
| `driftseal --version` 或 `driftseal -V` | 输出当前安装的 DriftSeal 版本。 |
|
|
268
|
-
| `driftseal help` | 查看 CLI 用法。 |
|
|
269
|
-
|
|
270
|
-
如果 `begin` 通过一个或多个 `--decision <id>` 声明了关联,那么 intent
|
|
271
|
-
以 `completed` 或 `partial` 关闭前,必须用 `driftseal decision update` reconcile
|
|
272
|
-
每一条关联 decision。update 可以改变当前 status,并会追加一条包含时间和
|
|
273
|
-
intent ID 的 history。没有关联 decision 的 intent 仍沿用普通流程。对于
|
|
274
|
-
acceptance-bound linked intent,所有 decision update 都必须发生在
|
|
275
|
-
`driftseal verify` 之前,因为 update 会改变 workspace fingerprint;顺序应当是
|
|
276
|
-
reconcile、verify、end。
|
|
277
|
-
|
|
278
|
-
## 回收已无意义的记录
|
|
279
|
-
|
|
280
|
-
有些已关闭的记录会随着时间失去意义:harness 或 sandbox 导致的失败会被如实记录为
|
|
281
|
-
`failed`,但它与项目本身无关。`driftseal reclaim` 可以在不改写历史的前提下让这类
|
|
282
|
-
记录退场——它只是向同一个 append-only log 追加一条 `reclaim` 标记(必须附带
|
|
283
|
-
`--reason`),被回收的记录会从 `driftseal log` 和 `driftseal status` 的输出中隐藏,
|
|
284
|
-
但仍保留在 `events.jsonl` 中,并可通过 `log --all` 查看。若事后发现某条记录仍然
|
|
285
|
-
重要,用 `driftseal unreclaim <id> --reason "..."` 恢复。
|
|
286
|
-
|
|
287
|
-
不带 id 的批量模式只回收已关闭、未关联 decision、且早于 `--older-than` 天(默认 7
|
|
288
|
-
天)的 `failed`/`abandoned` 记录;可以先用 `--dry-run` 预览。`completed` 和 `partial`
|
|
289
|
-
记录,以及任何关联了 decision 的记录,只能按显式 id 加 `--force` 回收。
|
|
290
|
-
|
|
291
|
-
## 一致性与恢复
|
|
292
|
-
|
|
293
|
-
DriftSeal 会对配置后的 intent log 与 decision log 根目录加锁,并按固定顺序获取这些
|
|
294
|
-
lock,从而串行执行 mutating commands。Decision reconciliation 会先写 prepare
|
|
295
|
-
event,再以 atomic replacement 更新 MADR,最后写 commit event。如果进程在中间
|
|
296
|
-
停止,下一次 linked `decision update` 或 successful `end` 会根据 content hash
|
|
297
|
-
恢复 transaction。linked intent 成功关闭前,还会验证 decision 文件自最近一次
|
|
298
|
-
reconciliation 后没有发生变化。未关联 decision 的 intent 不会解析 decision log;
|
|
299
|
-
当 decision recovery 无法完成时,`failed` 与 `abandoned` 仍可作为退出路径。
|
|
300
|
-
这两个 terminal status 会取消对应 pending transaction 的后续 recovery;同时,
|
|
301
|
-
recovery 只处理当前 intent,因此历史冲突不会阻塞之后的 decision 工作。
|
|
302
|
-
|
|
303
|
-
新 event 带有 schema version。遇到更高且不支持的版本时,DriftSeal 会拒绝继续;如果
|
|
304
|
-
旧 client 未经 reconciliation 就关闭 linked intent,新 client 也会 fail closed。
|
|
305
|
-
`driftseal init` 会写入带版本的 managed blocks,并且只升级内容完全匹配的已知旧版本。
|
|
306
|
-
当前版本的 block 如果只是 log language 不同,也会被识别,因此可以用 `--lang`
|
|
307
|
-
改语言而不必手改协议。遇到更新的协议版本、无法识别的 block 或自定义内容时,
|
|
308
|
-
它会保持 `AGENTS.md` 不变并拒绝继续。
|
|
309
|
-
|
|
310
|
-
`--count` 只输出 status 筛选后的记录总数。它不能与 `--last` 一起使用,以免
|
|
311
|
-
“先限制再计数”造成歧义。Decision 文件名会构成一个轻量的内存索引:`show` 只
|
|
312
|
-
解析目标 record;不带 status 的 `--count` 完全不读取 MADR 正文。按 status 筛选
|
|
313
|
-
时仍需解析全部 records,因为 status 保存在各个 MADR 文档中;DriftSeal 不维护容易
|
|
314
|
-
滞后的 sidecar index。
|
|
315
|
-
|
|
316
|
-
## 合并 worktree
|
|
317
|
-
|
|
318
|
-
两条 worktree 各自按本地日志分配 intent / decision id,同一天并行 `begin` 或 `decision add`,分支合并时就会撞号。`driftseal absorb` 保留我方编号、给进来的一侧重编号,并打印对照表。单线 WAL 仍然只追加;absorb 是唯一允许的跨谱系重写。
|
|
218
|
+
在 Git worktree 中,`begin` 会把 open outcome park 到 Git metadata,避免弄脏 tracked
|
|
219
|
+
log;`end` 再把完整 lineage 写入 `.seal/outcomes/events.jsonl`。正常工作期间 event log
|
|
220
|
+
保持 append-only。
|
|
221
|
+
|
|
222
|
+
发生 merge collision 后执行:
|
|
319
223
|
|
|
320
224
|
```sh
|
|
321
|
-
driftseal absorb
|
|
322
|
-
--decisions ../other-worktree/.decision-log
|
|
225
|
+
driftseal absorb
|
|
323
226
|
```
|
|
324
227
|
|
|
325
|
-
|
|
228
|
+
不要手改 JSONL。`absorb` 会给撞号的 outcome 与 decision id 重新编号,重新绑定受影响的
|
|
229
|
+
contract hash,并拒绝自动合并 shared MADR 的并发编辑。若两条 lineage 都处于 open
|
|
230
|
+
状态,必须显式选择 `--abandon-theirs` 或 `--abandon-ours`。
|
|
231
|
+
|
|
232
|
+
## Node API 与 MCP
|
|
233
|
+
|
|
234
|
+
```js
|
|
235
|
+
const { createApi } = require('driftseal');
|
|
326
236
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
237
|
+
const seal = createApi({ root: process.cwd(), isolateStorage: true });
|
|
238
|
+
seal.begin({
|
|
239
|
+
outcome: 'Ship account recovery',
|
|
240
|
+
acceptance: ['the recovery tests pass'],
|
|
241
|
+
verify: 'npm test',
|
|
242
|
+
});
|
|
243
|
+
seal.extend({ extension: 'Document token expiry' });
|
|
244
|
+
```
|
|
332
245
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
时执行,不必为了清工作树而多做一个只含日志的提交。`end` 会先把停放的记录移入跟踪
|
|
336
|
-
日志,再把关闭记录写在那里,而不会写进 Git 元数据;因此 `end` 中途失败时,intent
|
|
337
|
-
只是以未关闭状态留在日志里,重跑一次即可。如果停放中的 intent id 与合并进来的事件
|
|
338
|
-
撞号,DriftSeal 会按 `absorb` 同样的规则重编号。
|
|
246
|
+
API 还提供 `status`、`verify`、`end`、`log`、`absorb`、reclaim、decision、init 与
|
|
247
|
+
migration 方法。
|
|
339
248
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
放弃所有未关闭的 intent。
|
|
249
|
+
stdio MCP server 会把所有操作固定在一个 repo root。v2 tools 包括
|
|
250
|
+
`driftseal_status`、`driftseal_begin`、`driftseal_extend`、`driftseal_verify`、
|
|
251
|
+
`driftseal_end`、outcome history/absorb、MADR,以及三个 migration tools。resources 为:
|
|
344
252
|
|
|
345
|
-
|
|
253
|
+
- `driftseal://outcome/current`
|
|
254
|
+
- `driftseal://outcomes/recent`
|
|
255
|
+
- `driftseal://madr`
|
|
346
256
|
|
|
347
|
-
|
|
348
|
-
- `.decision-log/`:编号化的 MADR decision records。
|
|
349
|
-
- 设置 `DRIFTSEAL_HOME` 或 `DRIFTSEAL_DECISION_HOME`,即可把对应 log 放到当前项目之外。
|
|
257
|
+
## 存储与信任边界
|
|
350
258
|
|
|
351
|
-
|
|
259
|
+
- `.seal/outcomes/events.jsonl` 是 append-only outcome log。通过 DriftSeal 访问它;
|
|
260
|
+
需要调整可见性或处理 merge 时使用 `reclaim`、`unreclaim`、`absorb`,不要手改。
|
|
261
|
+
- `.seal/madr/` 保存编号化 MADR。
|
|
262
|
+
- `$DRIFTSEAL_HOME` 替换整个 `.seal` root。
|
|
263
|
+
- advisory hook 只提示 lifecycle 状态,不会扩大 repo 中 `AGENTS.md` 的政策边界。
|
|
352
264
|
|
|
353
|
-
|
|
265
|
+
DriftSeal 不会替你判断 verification command 是否安全,也不会判断测试本身是否充分。
|
|
266
|
+
执行前应检查命令,并继续遵守正常的 repo 授权与安全规则。
|
|
354
267
|
|
|
355
|
-
##
|
|
268
|
+
## 开发
|
|
356
269
|
|
|
357
270
|
```sh
|
|
358
271
|
npm test
|
|
272
|
+
node --check bin/driftseal.js
|
|
273
|
+
node --check bin/driftseal-mcp.js
|
|
274
|
+
npm pack --dry-run
|
|
359
275
|
```
|
|
360
276
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
## License
|
|
364
|
-
|
|
365
|
-
MIT,详见 [`LICENSE`](LICENSE)。
|
|
277
|
+
使用 MIT License。
|