task-ledger 1.2.9 → 1.3.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.
Files changed (55) hide show
  1. package/README.md +29 -245
  2. package/SKILL.md +173 -88
  3. package/package.json +22 -22
  4. package/references/log-note.md +3 -1
  5. package/references/state-model.md +29 -27
  6. package/references/troubleshooting.md +98 -25
  7. package/scripts/ledgerkit/__init__.py +0 -0
  8. package/scripts/ledgerkit/actions/__init__.py +0 -0
  9. package/scripts/ledgerkit/actions/atom.py +154 -0
  10. package/scripts/ledgerkit/actions/bootstrap.py +27 -0
  11. package/scripts/ledgerkit/actions/claim.py +82 -0
  12. package/scripts/ledgerkit/actions/close_task.py +180 -0
  13. package/scripts/ledgerkit/actions/guard.py +140 -0
  14. package/scripts/ledgerkit/actions/handoff.py +74 -0
  15. package/scripts/ledgerkit/actions/list_tasks.py +53 -0
  16. package/scripts/ledgerkit/actions/log_progress.py +60 -0
  17. package/scripts/ledgerkit/actions/new_task.py +120 -0
  18. package/scripts/ledgerkit/actions/query.py +33 -0
  19. package/scripts/ledgerkit/actions/query_history.py +173 -0
  20. package/scripts/ledgerkit/actions/registry.py +82 -0
  21. package/scripts/ledgerkit/actions/release.py +51 -0
  22. package/scripts/ledgerkit/actions/result.py +88 -0
  23. package/scripts/ledgerkit/actions/set_task.py +43 -0
  24. package/scripts/ledgerkit/actions/show_task.py +27 -0
  25. package/scripts/ledgerkit/actions/validate.py +224 -0
  26. package/scripts/ledgerkit/core/__init__.py +0 -0
  27. package/scripts/ledgerkit/core/history_md.py +350 -0
  28. package/scripts/ledgerkit/core/identity.py +43 -0
  29. package/scripts/ledgerkit/core/ids.py +58 -0
  30. package/scripts/ledgerkit/core/labels.py +79 -0
  31. package/scripts/ledgerkit/core/paths.py +93 -0
  32. package/scripts/ledgerkit/core/time.py +102 -0
  33. package/scripts/ledgerkit/core/worklog_md.py +232 -0
  34. package/scripts/ledgerkit/env.py +93 -0
  35. package/scripts/ledgerkit/errors.py +15 -0
  36. package/scripts/ledgerkit/notices.py +28 -0
  37. package/scripts/ledgerkit/shell/__init__.py +0 -0
  38. package/scripts/ledgerkit/shell/cli.py +259 -0
  39. package/scripts/ledgerkit/shell/gitops.py +655 -0
  40. package/scripts/ledgerkit/shell/merge.py +266 -0
  41. package/scripts/ledgerkit/shell/presync.py +23 -0
  42. package/scripts/ledgerkit/shell/render.py +165 -0
  43. package/scripts/ledgerkit/shell/runner.py +225 -0
  44. package/scripts/ledgerkit/store/__init__.py +0 -0
  45. package/scripts/ledgerkit/store/atomic.py +130 -0
  46. package/scripts/ledgerkit/store/dirty.py +108 -0
  47. package/scripts/ledgerkit/store/history_store.py +189 -0
  48. package/scripts/ledgerkit/store/json_store.py +166 -0
  49. package/scripts/ledgerkit/store/locks.py +64 -0
  50. package/scripts/ledgerkit/store/owners_index.py +135 -0
  51. package/scripts/ledgerkit/store/task_store.py +31 -0
  52. package/scripts/ledgerkit/store/worklog_store.py +168 -0
  53. package/scripts/progress.py +8 -3021
  54. package/references/taxonomy.md +0 -26
  55. package/references/worklog.md +0 -39
package/README.md CHANGED
@@ -1,265 +1,49 @@
1
1
  # task-ledger
2
2
 
3
- > 这份文档**给人看**:它是什么、为什么这么设计、一次调用背后发生什么。
4
- > 给 agent 的执行说明在 `SKILL.md`,两者不重复;`SKILL.md` 里**没有**引用本文件,所以它不会进 agent 上下文、不占 token。
3
+ > 给人看的概览与索引。给 agent 的执行说明在 `SKILL.md`(每次会话整份注入),两者不重复;本文件不进 agent 上下文、不占 token。
5
4
 
6
- ## 一、它做什么
5
+ ## 它做什么
7
6
 
8
- 管一个项目 / 工作区的任务进度(开发活、琐事、调研、备忘都算),一共三件东西:
7
+ 管一个工作区 / 项目的任务进度(开发活、琐事、调研、备忘都算),一共三件东西:
9
8
 
10
- | 管什么 | 落在哪 | 谁写 |
11
- |---|---|---|
12
- | 在办任务的状态 | `ledger/progress.json` | **只由脚本写** |
13
- | 每个任务的过程正文 | `ledger/worklog/<年月>/<日>-<时分>-<说明>-<随机码>.md` | **建档只由脚本按模板做**,之后正文 **agent 直接编辑** |
14
- | 已结案任务,一行一条(9 列:结案时间 / 创建时间 / 工作包 / 分类 / 标签 / owner / creator / 摘要 / 过程文档) | `ledger/history/<年月>.md`(按**结案时间**分月;存量 `ledger/PROGRESS-HISTORY.md` 只读兼容、永不重写) | **只由脚本写**;查询走 `history` 子命令 |
9
+ - **谁在做、做到哪**:状态只在台账 JSON —— `ledger/pool.json`(公共池)+ 每人一份 `ledger/owners/<hash>.json` 分片,索引 `ledger/owners.json`。
10
+ - **过程正文**:全在 `ledger/worklog/<年月>/<月日>-<时分>-<说明>-<码>.md`(六节),agent 直接编辑前五节,末节「执行记录」只由脚本写。
11
+ - **已结案**:一行一条在 `ledger/history/<年月>.md`(9 列),只由脚本写。
15
12
 
16
- 覆盖的动作:建任务、认领、交接、改状态、结案、查在办、查历史、体检。
13
+ 状态改动与正文重写分开、全部经脚本改 —— 不另建副本、不手改状态表和历史。覆盖动作:建任务、认领、释放、结案、查在办、查历史、标签归并、体检。
17
14
 
18
- 典型场景:
15
+ ## 文件布局(脚本只写这些)
19
16
 
20
- - 问「现在该做什么 / 我还有什么没做完」→ 查在办
21
- - 说「新建一个任务 / 这活我领了 / 卡住了 / 转给某人 / 这活做完了」→ 改状态或结案
22
- - 问「某件老活是什么时候做的」「谁改过什么」「拉某人的工作日志」→ `history` 子命令(只读,可直接跑)
23
-
24
- ## 二、为什么这么设计
25
-
26
- ### 顶层目录为什么是 `ledger/`,不是 `docs/`
27
-
28
- `docs/` 是**项目自己的地盘** —— 项目的文档规范、设计、样例都住在那里,各有各的规矩。
29
- 把进度三件套塞进 `docs/`,等于让「进度管理」去占用别人已经安排好的空间;
30
- 换一个没有 `docs/` 的项目、或项目把 `docs/` 用作别的用途,就又得重新商量放在哪。
31
-
32
- 所以本 skill 统一用**独立的 `ledger/` 目录**:任何项目、任何工作区都用同一个名字,
33
- 既不依赖项目原有的 `docs/`,也不与它发生关系(项目原有 `docs/` 原样不动、不进本体系)。
34
- 进度是「跨项目长一个样」的东西,就该有一个跨项目固定的家。
35
-
36
- ### 状态用 JSON,不用 Markdown
37
-
38
- 状态要频繁改(`open` → `doing` → 结案),Markdown 里改一个词很容易顺手改到别处。JSON 结构化、字段固定、一次只动一个值,改动面最小。
39
-
40
- ### 状态与过程正文分离
41
-
42
- 状态改动频繁、正文频繁重写,混在一个文件里必然互相踩。所以拆成两个文件:**JSON 只放数据,正文全在 `worklog/`**。JSON 里一个字的过程描述都不放 —— 一旦开始写段落,改动面就不可控了。
43
-
44
- 唯一进 JSON 的「文档类」信息是过程文档的**路径**(`worklog` 字段,如 `worklog/202610/06-0000-doc-arch-review-7a3c.md`)。它不是描述而是索引:按月分目录之后文件名不再等于任务号,靠推算容易找错,记一笔最省事。
45
-
46
- ### 历史层的 owner 是独立列
47
-
48
- 「谁改过什么」「拉某人的工作日志」靠 `history --owner` **精确匹配**。owner 必须独立成列,不能缝在工作包标题里:缝进去就只能文本搜索,`a` 会命中 `a-11`;切分也只能靠「最后一个 ` @`」这种启发式,标题里出现 `@`(如 `rulemux@0.1.0`)就切错。独立列让按人查退化成列比较,与 `list --owner` 查在办是同一套精确语义。
49
-
50
- ### 记录时间精确到秒,任务号 / 文件名只到分
51
-
52
- 两者用途不同,精度也不同:**任务号、worklog 目录与文件名**只到分(`年月日-时分` / `YYYYMM`)—— 够排序、够肉眼定位,且短;**所有记录时间**(`progress.json` 的 `created` / `started` / `finished`、历史表的时间列、worklog 头部的创建 / 封卷行)到**秒** —— 按时间段检索、比对都靠它,分不够。
53
-
54
- 写入前一律经 `normalize_time` 归一化:`2026-10-06`、`2026-10-06 14:30`、`2026-10-06 14:30:05` 都接受,缺的补 `00:00:00`。读旧数据时又**兼容只到分**的写法(老历史行照读不误),只有新写入的才带秒。
55
-
56
- ### 历史表为什么带创建时间
57
-
58
- 历史层的过滤口径是**创建时间**(`list` / `history` 的 `--since` / `--until` 都按它),因为「这活是什么时候建的」比「什么时候被结案」更常用、也更稳。所以历史行同时存**结案时间**(第一列)与**创建时间**(第二列)。升级旧行时创建时间先读它链接的 worklog 头部「创建」行,读不到用升级时刻 —— 不留空。
59
-
60
- ### 历史层为什么按月归档
61
-
62
- `close` 每结案一行就往历史层追加,早期是单一文件 `ledger/PROGRESS-HISTORY.md`:项目一两年下来它无限增长,每次结案都要整文件读入、升级、重写 —— 结案成本随历史总量线性变差。
63
-
64
- 现在按**结案时间**分月落 `ledger/history/<年月>.md`,与 worklog 的 `ledger/worklog/<年月>/` 同构:
65
-
66
- - **写入时分月,不做定时外挪** —— 外挪需要一个「谁定时触发」的角色,必然漂移;写入时分月零新增动作,且结案只碰当月小文件
67
- - **存量文件原地只读** —— 改造前的 `ledger/PROGRESS-HISTORY.md` 永不重写、永不删除,读侧 glob 兼容;它里面的旧格式行也不会被自动升级(读侧三格式兼容 + `validate` 提示已覆盖)
68
- - **文档链接跟着所在文件走** —— 行里的 worklog 链接相对该行所在的历史文件目录解析:存量文件里是 `worklog/…`,月文件里是 `../worklog/…`,两边都可点击、可定位
69
- - **查询无感** —— `history` / `validate` 合并全部来源,过滤、排序、`--json` 行为不变;行尾附所在历史文件,`--json` 记录带 `src` 字段
70
-
71
- ### 状态文件只由脚本写
72
-
73
- 两个人(或两个 agent)同时编辑同一个文件会互相覆盖。脚本的写入靠两层保证:
74
-
75
- 1. **原子替换**:先写同目录的临时文件,再 `os.replace` —— 保证文件不会出现半截内容
76
- 2. **写前复查指纹**:读的时候记下文件的**内容哈希**(sha256),写之前再比一次;变了就报错中止、要求重跑。
77
- 刻意不用 mtime+size —— 并发写入可能落在同一时间精度内、字节数又恰好相同,那样指纹不变,复查就形同虚设
78
-
79
- 第 2 条是**发现并中止**,不是自动合并 —— 它把「静默覆盖别人」变成「明确报错让你重来一次」。所以并发下偶尔会遇到「被改动过,重跑」,这是设计如此,不是 bug。
80
-
81
- ### worklog 头部只写不会变的东西
82
-
83
- 原设计里 worklog 头部带 `状态:open · owner:(待认领)`,实测发现:**`claim` 之后头部还写着 `open`,成了过期副本**。删掉 —— 状态真源只有 `progress.json` 一个。
84
-
85
- 现在头部只写两样**写入后就不再变**的:**创建时间 + 创建人**(`new` 建档时写)、**封卷时间 + 封卷人**(`close` 结案时追加)。会变的东西(状态、当前 owner)一律不写。
86
-
87
- ### 任务号 = 创建时间 + 语义名 + 4 位随机码
88
-
89
- `登录接入 SSO`(2026-10-15 14:30 建的)→ `20261015-1430-登录接入-sso-1eed`。
90
-
91
- - 前置 `年月日-时分`:一眼看出这个任务是什么时候建的,也天然按时间排序
92
- - 中段语义名:一眼知道是什么任务(所以保留汉字,纯中文标题也能生成)
93
- - 后缀 4 位随机码:**必须保留** —— 任务号只在在办任务里去重,而 worklog 结案后仍留在磁盘上,去掉随机码会让新任务与已结案的过程文档同名、覆盖历史
94
- - 不用纯 UUID:文件名会变得完全不可读
95
- - 想自己指定就传 `--id`
96
-
97
- ### owner 只认 git 身份,不做兜底
98
-
99
- `owner` 一律取 `git config user.name`。取不到就**直接报错退出**(提示「需要用户名才能执行」),没有默认值、没有备选标识、没有降级路径。
100
-
101
- 理由:拿一个编造的身份去写"谁在做这个任务",比写不进去危险得多。
102
-
103
- ### 只能改自己的任务
104
-
105
- `set`、`close` 和 `log` 都先取身份,再校验「这个任务的 owner 是不是你」:**不是就拒绝**;任务还没人认领(`open`)也拒绝,提示先 `claim`。要接手就走 `set --owner` 交接 —— 一次显式动作。
106
-
107
- 理由有两层:一是别人替你结案,你会失去对进度的掌控;二是如果只取了身份却不校验归属,`owner` 这个字段就只是个装饰品。
108
-
109
- ### 不依赖任何框架注入的变量
110
-
111
- 早先写成 `{baseDir}/scripts/progress.py` —— 那是某一家的注入变量,换个 harness 就没有。现在写成「本 SKILL.md 所在目录」这种不依赖注入的表述。
112
-
113
- 同理,**项目位置必须由调用方用 `--repo` 传**:脚本只知道自己在哪,不可能知道你现在在哪个项目里干活。
114
-
115
- ### 并发策略
116
-
117
- - 所有写命令(`init` / `new` / `claim` / `set` / `log` / `close`)走同一套:**读 → 改内存 → 复查指纹 → 原子写**
118
- - 临时文件名唯一(`mkstemp`),写完 `fsync` 再 `os.replace`,无论成败都清理临时文件
119
- - key 按字母序落盘,减少两人同时新增时的文本冲突
120
- - 冲突时**报错要求重跑**,不静默覆盖
121
- - 写入成功后脚本会**自动同步**:把本次改动的台账文件 `git add <精确文件>` + `commit`(消息 `chore(ledger): <命令> <提交者>`,即 conventional commits 格式,多数仓库装了 commitlint 也认);当前分支有上游跟踪分支时再 `push`。全程确定性脚本,不依赖大模型
122
- - 仓库若装了自定义提交检查并拒了这条消息,脚本会**再用 `--no-verify` 提交一次**(台账是数据文件,不过 lint);仍失败则把 git 的报错打到 stderr 并要求手动提交 —— **同步失败绝不静默**,但退出码保持 0(台账本身已写成功)
123
- - 写前会**定向取最新**:只刷新 `ledger/progress.json` 与 `ledger/history/`(这两个只由脚本写);`ledger/worklog/` 里已有的正文一个字都不动,只在本地缺文件时补下远端的新文件(补下的文件随本次提交入库)。本地有未推送的台账提交、未提交改动、或未入库的同名文件时**中止**,不静默覆盖;命令随后失败时,写前刷下来的内容会回滚原样
124
- - 本地**没有未推送提交**时,写前会先 fast-forward 到上游(只快进、不产生合并提交);有未推送提交就跳过,退回上面那条的定向刷新
125
- - 同一个 clone 里的写命令**排队**执行(仓级文件锁,最多等 60 秒),避免两个 agent 同时写时,一个把另一个刚写完还没提交的改动静默覆盖
126
- - 写后推送被拒时,工作树干净才自动 `rebase` 一次再推(各自改各自的任务时按行自动合并);冲突立刻 `rebase --abort`,绝不 `--force`、绝不留 rebase 中间态
127
- - 无 git 仓库 / 无上游跟踪 / 被 `.gitignore` 排除 / 无实际变更 都会静默跳过;`--no-sync` 或环境变量 `TASK_LEDGER_NO_SYNC=1` 可同时关掉写前取最新与写后同步
128
-
129
- ### 结案是原子操作
130
-
131
- `close` 一次完成三件事,**顺序是有意排的**:先写历史索引 → 再封卷过程文档 → **最后**才从状态表里移除。
132
-
133
- 为什么是这个顺序:万一中途崩溃,最坏结果是「历史多了一行、状态表里任务还在」,重跑一次就对上了;反过来先删状态、后写历史,崩溃会让任务**既不在状态表、也不在历史** —— 记录凭空消失。
134
-
135
- 落盘时任一步失败会**整体回滚**,并逐文件报告哪些恢复成功、哪些没成功(回滚本身失败时不会掩盖原始错误)。
136
-
137
- ### 分类与标签为什么不设枚举
138
-
139
- 本 skill 跨所有工作区使用(开发 / 运维 / 个人事务 / 调研备忘都算),任何固定枚举都覆盖不全、颗粒度难定;「让 Agent 判断会不准」也不能靠穷举分类消解。所以分两层、都自由:
140
-
141
- - **`category` 单值**:答「这事是什么类型」。一条一值,`count by` 干净,是人眼扫视和看板统计的轴
142
- - **`tags` 1~5 个**:答「这事涉及什么」(对象 / 领域 / 模块)。兜住长尾与新领域,写错了只影响一个切面
143
-
144
- 两层都只硬校验**形态**(≤4 字 / 纯英文 ≤3 词 / ≤5 个),不校验语义 —— 语义 correctness 交给口径(SKILL.md 的归一化规则 + 正反示例)和巡检归并机制,不交给枚举。
145
-
146
- ### category 精确匹配、tag 包含匹配
147
-
148
- 两种查询语义不同是有意的:category 是统计轴,同值才能比较,必须精确;tag 是容错下钻,「bug」命中「bug修复」正是包含匹配要的效果 —— 它天然吃掉一部分同义变体,剩下的漂移靠 `tags --all` 暴露、`tags --rename` 归并。
149
-
150
- ### 为什么只硬校验上限、不设标签数量下限
151
-
152
- 设下限(如必须 3 个标签)会逼 Agent 凑数 —— 凑出来的正是噪声,与「容忍错误」的初衷相反。上限(≤5)与字数(≤4 字 / 英文 ≤3 词)是形态红线,必须硬校验;数量只引导、不强制。
153
-
154
- ### 分类/标签进 history 列(2026-10-15 存量改造时加入)
155
-
156
- 初版设计是「不进列、回链读」:history 解析写死 6 列,加列要迁移存量。用户评审时要求反转——已结案记录也要能按分类/标签查,于是升为 **8 列**(结案时间 / 创建时间 / 工作包 / 分类 / 标签 / owner / 摘要 / 过程文档):
157
-
158
- - `close` 从 task 直写分类/标签终值(`--category`/`--tags` 覆盖过的用覆盖值)
159
- - 存量 4/5/6 列由 `upgrade_history` 升级为 8 列:分类/标签**回链该行 worklog 头部**读(`labels_for_log`,与 created 回填同一模式),读不到留空、不编造
160
- - 回链没有废弃:`history` 子命令对仍是 4/5/6 列的旧行(未升级文件)继续回链兜底,`cmd_history` 里「列空才回链」
161
-
162
- 代价说清:加列动了 parse/upgrade/close 全链路,靠「逐行按自己列数判别 + 不敢升级就按原列数追加」的老机制兜底;冒烟覆盖了 8 列写入、6 列升级(owner 剥 @ 防 `@@`)、4 列升级、坏行退回四条路径。
163
-
164
- ### rename 为什么不碰已封卷文档
165
-
166
- 与「封卷即不可变」同一哲学:rename 只改状态表与在办 worklog 头部;已结案记录的旧标签留在原文档里。这类残留在 `tags --all` 的频次表里可见,看板侧自行归并 —— 台账只做记录,不做历史改写。
167
-
168
- ### 「分类/标签」行为什么由 render 动态插入
169
-
170
- 不占模板占位符 ⇒ `assets/worklog.md` 与 `FALLBACK_TEMPLATE` 都不用改,两个模板永远一致;空值(存量任务、Agent 没总结)自动不写行,向后兼容零成本。生成、解析、覆盖三处共用 `label_line` 一个格式定义,防漂移。
17
+ | 文件 | 装什么 |
18
+ |---|---|
19
+ | `ledger/pool.json` | 公共池:未认领任务(owner 空) |
20
+ | `ledger/owners.json` | 索引:git 邮箱身份 → 分片文件 |
21
+ | `ledger/owners/<hash>.json` | 每人一份分片:自己认领的任务 |
22
+ | `ledger/worklog/<年月>/*.md` | 任务正文(六节) |
23
+ | `ledger/history/<年月>.md` | 已结案(一行一条,9 列) |
171
24
 
172
- ## 三、运行逻辑
25
+ ## 为什么这么设计
173
26
 
174
- ### 一次调用发生什么
27
+ 跨项目固定用 `ledger/`(不占项目的 `docs/`);状态用 JSON 而非 Markdown(改动面最小);状态与过程正文分离(互不踩);一人一份分片把并发冲突面从整份文件缩到公共池里几行;台账数据时间存 UTC、过程文档里的日志行显示本地时间。
175
28
 
176
- ```mermaid
177
- graph LR
178
- U[用户说一句话] --> A[agent 读 SKILL.md 判断意图]
179
- A -->|只读直接跑| R[list / show / validate / history]
180
- A -->|写操作| W[init / new / claim / set / log / close]
181
- W --> P[ledger/progress.json]
182
- W --> H[ledger/history/年月.md]
183
- W --> M[ledger/worklog/年月/日-时分-说明-码.md]
184
- A -->|直接编辑| M
185
- A -->|只读查询| H
186
- W -->|返回该任务文档全文| A
187
- ```
29
+ ## 怎么用(执行规则在 SKILL.md)
188
30
 
189
- ### 状态机
31
+ 直接跑:
190
32
 
191
- ```mermaid
192
- stateDiagram-v2
193
- [*] --> open: new(不带 --self)
194
- [*] --> doing: new --self
195
- open --> doing: claim(认领,写 owner)
196
- doing --> open: set --status open(释放认领,清空 owner)
197
- doing --> [*]: close(进历史)
198
- note right of doing
199
- set --owner 交接:owner 换成别人
200
- (只有当前 owner 能执行)
201
- 逾期 = 接任务满 14 天;停滞 = 最后更新满 3 天
202
- 积压 = 待认领满 30 天
203
- (都由看板按时间算,不是状态)
204
- end note
33
+ ```bash
34
+ python3 <SKILL.md 所在目录>/scripts/progress.py <子命令> --repo <当前工作区>
205
35
  ```
206
36
 
207
- - `done` **只能由 `close` 产生**;`set --status done` 会被拒绝
208
- - **退回未认领**:owner 用 `set --status open` 把任务退回去,owner 清空、之后别人可以重新 `claim`;这条不能与 `--owner` 同时给
209
- - `set --owner <某人>` 是**交接**,由当前 owner 执行,执行后 owner 换成那个人。**该能力只为将来的 UI 保留**:SKILL.md 不向 agent 暴露它,换人一律走「释放 → 认领」,避免随便编一个名字挂上去
210
- - 状态表里不允许残留 `done`(`validate` 会报)
211
-
212
- ### 命令一览
37
+ 子命令:`new` `claim` `set` `log` `close` `list` `history` `show` `tags` `validate`。命令参考(参数 / 一句话 / 举例)、任务生命周期、纪律(数据完整性 / 人类授权 / 故障处置)全在 `SKILL.md`;参数细节看 `<子命令> --help`(不要凭记忆编)。
213
38
 
214
- | 子命令 | 作用 | 需要 git 身份 | 会返回任务文档全文 |
215
- |---|---|---|---|
216
- | `init` | 建状态表 | 否 | 否 |
217
- | `new` | 建任务并建档 | **是**(记 creator) | 是 |
218
- | `claim` | 认领待认领任务 | **是** | 是 |
219
- | `set` | 改状态 / 交接 / 释放认领(`--status open`) | **是**(且必须是该任务的 owner) | 是 |
220
- | `log` | 往 worklog「执行记录」补一条 | **是**(且必须是该任务的 owner) | 否(只回一行确认) |
221
- | `close` | 结案归档 | **是**(且必须是该任务的 owner) | 否 |
222
- | `list` | 查在办任务 | 仅 `--mine` | 否 |
223
- | `history` | 查已结案任务(只读) | 仅 `--mine` | 否(只给过程文档链接) |
224
- | `show` | 单任务详情 | 否 | 是 |
225
- | `tags` | 分类/标签巡检(`--all` 只读)/ 归并(`--rename` 批量写) | 否 | 否 |
226
- | `validate` | 校验一致性 | 否 | 否 |
39
+ ## 深入参考(references/,按需读)
227
40
 
228
- 参数细节看 `SKILL.md`,或直接跑 `<子命令> --help`。
229
-
230
- ### 返回什么
231
-
232
- | 命令 | 返回 |
41
+ | 文件 | 看什么 |
233
42
  |---|---|
234
- | `new` / `claim` / `set` / `show` | 状态行 + 该任务过程文档的**路径与全文** |
235
- | `log` | 一行确认(记了什么) |
236
- | `close` | 结案结果与摘要 |
237
- | `list` | 在办任务列表(不含正文,避免撑爆上下文) |
238
- | `history` | 已结案紧凑列表(默认不含摘要,避免撑爆上下文) |
239
-
240
- 返回文档全文是有意的:agent 拿到就能直接编辑,不用再去找文件、拼路径。
241
- `history` 是唯一的例外:只回过程文档的**链接**,正文另读 —— 历史层摘要就是这套体系里唯一的「正文」,默认不吐。
242
-
243
- ### 失败约定
244
-
245
- | 情况 | 行为 |
246
- |---|---|
247
- | 成功 | 退出码 0 |
248
- | 业务错误(参数值 / 状态 / 权限不对) | 输出到 stderr,**退出码 1**,消息以「错误:」开头 |
249
- | 命令行参数错误(argparse) | 退出码 2 |
250
- | 未预期的内部失败 | 输出到 stderr,**退出码 3**(与可纠正的业务错误区分开) |
251
- | 用户中断 | 退出码 130 |
252
- | 输出被下游截断(如 `\| head`) | 静默退出,退出码 0,不打 traceback |
253
-
254
- **报错就停下并原样报告,不要绕过脚本直接改 `ledger/progress.json` 或历史层(`ledger/history/<年月>.md`)。**
255
-
256
- ## 四、已知边界与待办
257
-
258
- 1. 本 skill 位于工作区 `_Skills/task-ledger/`;是否安装到全局 skill 目录由使用者决定 —— 未安装时其它项目不会自动触发。
259
- 2. `scripts/progress.py` 里的 `FALLBACK_TEMPLATE` 是**无注释的最小骨架**,只在 `assets/worklog.md` 读不到时启用 —— 两处注释多寡不同不是缺陷,**正例只放模板文件**。
43
+ | [`references/state-model.md`](references/state-model.md) | 状态机、时间口径(UTC / 本地、补录、筛选)、任务号、身份 |
44
+ | [`references/log-note.md`](references/log-note.md) | 执行记录什么算一个节点、`--note` 怎么写(正 / 反例) |
45
+ | [`references/troubleshooting.md`](references/troubleshooting.md) | 退出码、常见错误、硬约束、环境要求(git ≥ 2.27) |
260
46
 
261
- ## 五、维护者须知
47
+ ## 本仓自己的台账
262
48
 
263
- - `SKILL.md` 的 frontmatter `version` 与 `package.json` 的 `version` 保持同值;发版时一起改,打 `skill-v<version>` tag。
264
- - **`SKILL.md` 是每次会话整份注入的**:只放「不做就会写错数据」的规则与路由,细节进 `references/`(按需读,索引在 SKILL.md 末尾)。加体积前先自问「脚本或 `--help` 能不能兜住」。
265
- - 改完跑 `cd packages/plugin && npm run verify`(build + typecheck + smoke);`copy-skill` 会把 `scripts/` `assets/` `references/` 一并拷进插件内嵌副本,不要直接改那份拷贝。
49
+ 本仓库(`dsh-task-ledger`)也用 ledgerkit 管自己的活,台账数据在 `ledger/`;它和本 skill 源码 `packages/skill/` 是两回事 —— **改 skill 请别动 `ledger/`**。
package/SKILL.md CHANGED
@@ -1,134 +1,219 @@
1
1
  ---
2
2
  name: task-ledger
3
- description: 本地任务台账,跨会话记录在办任务的归属、进度与起止。当用户要登记一件新的事(新建任务 / 建个坑 / 这活我领了)、记录已有任务的进展(接着做 / 记一条进展 / 这轮先记下)、查看任务状态或历史(现在该做什么 / 这活谁在做 / 上周做过什么)时加载;对某个具体任务要求结案或退回时,只认用户的明确指令;只是改代码、讨论方案时不要用。
4
- version: 1.2.9
5
- allowed-tools: Read,Write,Bash,Grep
3
+ description: 本地任务台账,跨会话记录在办任务的归属、进度与起止。当用户要登记一件新的事(新建任务 / 建个坑 / 这活我领了)、记录已有任务的进展(接着做 / 记一条进展 / 这轮先记下)、查看任务状态或历史(现在该做什么 / 这活谁在做 / 上周做过什么)、给任务结案或退回(做完了 / 验收通过 / 不做了 / 退回待认领)、整理标签或检查台账一致性时加载;只是改代码、讨论方案时不要用。
4
+ version: 1.3.0
5
+ allowed-tools: Read,Edit,Bash,Grep
6
6
  ---
7
7
 
8
8
  # task-ledger
9
9
 
10
- 台账只管三件事:**谁在做、做到哪、什么时候建 / 结**。状态只在 `progress.json`,叙事只在 worklog,**全部经脚本改**。
10
+ 管一个工作区的任务进度:**谁在做、做到哪、什么时候建 / 结**。
11
11
 
12
- ## 三个文件
12
+ - **数据落点与多人并行**:每个工作区下有一个 `ledger/` 目录,任务与进度以静态文件形式存放在里面。**多人协同必须有 git**;没有 git 只写本地,也能用。多人共用却没有 git,提醒用户。
13
+ - **任务状态**:`待认领(open)` = 建了还没人认领;`进行中(doing)` = 已认领、在做;`已结案` = 用户明确说结束后由 `close` 产生,此后只读。
14
+ - **操作方式**:台账的状态与归属只经命令改;唯一能手写的是过程文档前五节(见「手写边界」)。台账只记「建 / 做 / 结」和指向过程文档的链接;产出物本身按项目自己的约定落盘。
13
15
 
14
- | 文件 | 装什么 |
16
+ ## 手写边界
17
+
18
+ - **唯一能手写的是任务的过程文档(worklog)前五节**(怎么写见「过程文档」节);末节「执行记录」由脚本维护,**禁止手写、禁止手工添加**。
19
+ - **其他所有文件一律不许手改**:修改 / 删除 / 任何操作都走命令;手改台账文件即数据损坏。
20
+ - 台账看着不对劲(任务凭空少了、状态怪、分片对不上)⇒ **不要动手修**:让用户跑 `validate`(要连老月份和正文一起看就跑 `validate --deep`),把清单交给用户。
21
+
22
+ ## 命令参考
23
+
24
+ 九个子命令,前五个是写命令(`new`/`claim`/`set`/`log`/`close`),后四个全是查询类(`list` / `show` / `history` / `validate`);何时用哪个见「任务生命周期」。参数语法看 `<子命令> --help`;下表说每个参数干什么、何时用。
25
+
26
+ ### new — 建任务
27
+
28
+ | 参数 | 含义 |
15
29
  |---|---|
16
- | `ledger/progress.json` | 在办任务:标题 / owner / 状态 / 时间(`created` `started` `updated` `finished`)/ 分类标签 / 过程文档路径。**只由脚本写** |
17
- | `ledger/worklog/…md` | 任务正文,六节:背景 / 待办 / 下一步 / 过程 / 结论 / **执行记录**(末节) |
18
- | `ledger/history/<年月>.md` | 已结案,一行一条。**只由脚本写** |
30
+ | `--title "…"` | 任务标题(必填)—— 写任务核心、一句话说清干啥;它用来生成任务号和过程文件名,建议 4~20 字 |
31
+ | `--id` | 自定义任务号(一般不传;只能用小写字母、数字、汉字和连字符) |
32
+ | `--created` | 给过去漏记的任务补建时,补录实际创建日期(`YYYY-MM-DD`) |
33
+ | `--self` | 建并认领:直接归自己名下、状态「进行中」。仅当用户明确说「并开始做 / 并执行」时才用(判定见生命周期第 2 条) |
34
+ | `--category` / `--tags` | 分类 / 标签,口径见本节末尾 |
19
35
 
20
- 前五节你直接编辑;**末节「执行记录」只由脚本追加,一个字都不许手写**。
21
- 不另建副本、不手改状态表和历史、不自己拼 worklog 文件名(`new` 会建好并给路径)。
22
- **台账 ≠ 产出物**:成果按所在项目自己的约定落盘,台账只放「建/做/结」和指向成果的链接。
36
+ 干什么:建任务、按模板建好过程文档。不加 `--self` = 只建,落公共池等认领;加 `--self` = 建并认领。
23
37
 
24
- ## 什么时候用
38
+ 分类 / 标签口径(`new` 与 `close` 共用这组参数):`--category` 答「是什么类型」,单值,中文 ≤4 字 / 纯英文 ≤3 词,吃不准写「其他」;`--tags` 答「涉及什么」,0~5 个、逗号分隔,写不出就不传(传空串等于没传)。tags 不许写 category 的同义词;查询用 tags(包含匹配,见 `list --tag`)。名词性短语、中文优先。**在办任务的分类 / 标签一旦写下就改不了**,只有结案时用 `close --category` / `--tags` 写终值。正例:`--category 缺陷修复 --tags "镜像拉取,超时重试"`;反例:`--category 已完成登录修复`、`--tags 修 bug`。
25
39
 
26
- ❌ 项目没有 `ledger/` 且只是临时一次性的事 → 不要自动 `init`,先问。
27
- ❌ 只想改某任务正文 → 用 `show` 拿路径与全文直接改,不要另建 md;已结案的用 `history` 找链接。
40
+ 举例:用户说「新建个任务:把发布流程走通」→ `new --title "把发布流程走通"`(只建,不认领);用户明确说「新建个任务并开始做」→ `new --title "把发布流程走通" --self`。
28
41
 
29
- ## 意图 → 命令
42
+ ### claim — 认领
30
43
 
31
- | 用户说 | 动作 |
44
+ | 参数 | 含义 |
32
45
  |---|---|
33
- | 「现在该做什么」「我还有啥没做完」 | `list --mine` |
34
- | 「谁在做 X」「有哪些在办」 | `list`;在等认领的加 `--status open` |
35
- | 「这个任务到哪一步了」「这轮做了什么」 | `show --id`(任务 JSON + worklog 全文) |
36
- | 「某件老活什么时候做的」「谁做过哪些活」 | `history`(可按 `--owner` / `--since` 筛) |
37
- | 「哪些任务停太久」 | `list --json`:`updated` 满 3 天=停滞、`started` 满 14 天=逾期、`created` 满 30 天仍 `open`=积压(看板算,别改状态) |
38
- | 「新建一个任务」 | `new`(`--self` = 建完即认领) |
39
- | 「这活我领了」 | `claim`(只对 `open` 有效) |
40
- | 「开始做 / 接着做 X」 | 还是 `open` 就先 `claim`;已是 `doing` 就直接改正文 + `log` |
41
- | 「继续做」「推进一下」 | 改「下一步 / 过程」,再 `log --note "本轮做了 X,下一步 Y"` |
42
- | 「记一下这轮」「这段做完了」 | `log --id <任务号> --note "…"`(agent 可主动做) |
43
- | 「卡住了」「先放一放」 | 写清卡在哪(不改状态),再 `log` |
44
- | 「退回待认领」「让别人接」 | `set --status open`(记 `release`),回待认领 |
45
- | 「转给某人」 | **skill 不换人**:你先释放,对方自己 `claim`;不许替用户写别人的名字 |
46
- | 「彻底不做了」「取消这个任务」 | `close --summary "放弃:原因"`(需用户明说) |
47
- | 「做完了」「验收通过」「结案」 | `close`(需用户明说,见红线) |
48
- | 「把某任务过程补一下」 | `show --id` → 改前五节 → `log` |
49
- | 项目还没有台账 / 状态表可疑 | `init`(先问)/ `validate` |
50
- | 「标签太乱」「两个标签一个意思」 | `tags --all` 看频次 → `tags --rename 旧 新` |
51
-
52
- ## 命令怎么调
46
+ | `--id <任务号>` | 认领哪个(必填) |
47
+
48
+ 干什么:把公共池里的任务认领到自己名下,状态变「进行中」。已经在别人名下的会拒绝;已在自己名下的会提示无需重复。
49
+
50
+ 举例:用户说「这活我领了」→ `claim --id 20261023-1117-把发布流程走通-7f3a`。
51
+
52
+ ### set — 释放任务(退回公共池)
53
+
54
+ | 参数 | 含义 |
55
+ |---|---|
56
+ | `--id <任务号>` | 释放哪个(必填) |
57
+ | `--owner ""` | 固定传空串 —— 释放 |
58
+ | `--owner <别人>` | 把任务转交给对方(预留通道,**agent 不用**,见纪律) |
59
+
60
+ 干什么:把任务放回公共池、状态回「待认领」,别人即可认领;没有单独的「改状态」入口。
61
+
62
+ 举例:用户明确说「把这个任务退回去」→ `set --id <任务号> --owner ""`。
63
+
64
+ ### log — 记一条进展
65
+
66
+ | 参数 | 含义 |
67
+ |---|---|
68
+ | `--id <任务号>` | 哪条任务(必填)—— 只能给自己名下的任务记,不在名下会直接被拒 |
69
+ | `--note "…"` | 这条记录说什么(必填;一句话,含命令 / `文件:行号` / 符号名 / 结论之一) |
70
+
71
+ 干什么:刷任务的最后进度时间 + 在过程文档「执行记录」节追加一行。改正文必配一条 log(见纪律)。
72
+
73
+ 举例:一轮干完 → `log --id <任务号> --note "改了认领即 doing(claim.py:56);下一步同步文档"`。
74
+
75
+ ### close — 结案
76
+
77
+ | 参数 | 含义 |
78
+ |---|---|
79
+ | `--id <任务号>` | 结哪条(必填) |
80
+ | `--summary "…"` | 结案摘要(必填;放弃写「放弃:原因」) |
81
+ | `--finished` | 给漏记的旧任务补用时,补录实际结案时间(`YYYY-MM-DD[ HH:MM[:SS]]`) |
82
+ | `--category` / `--tags` | 覆盖分类 / 标签终值(写进历史行) |
83
+
84
+ 干什么:结案并封卷过程文档、移出自己名下。**封卷后只读**(见生命周期第 8 条)。
85
+
86
+ 举例:用户明确说「把这个任务结束掉」→ `close --id <任务号> --summary "发布流程走通,验证 25 项全过"`。
87
+
88
+ ### list — 查在办
89
+
90
+ | 参数 | 含义 |
91
+ |---|---|
92
+ | `--mine` | 只看自己名下的 |
93
+ | `--pool` | 只看公共池(没人认领的) |
94
+ | `--owner <邮箱>` | 看某个人的(精确匹配;邮箱在 `list --json` 里那个人名下的任务上能看到;没有 `me` 缩写) |
95
+ | `--status open\|doing` | 按状态筛(逗号分隔可多选;合法值只有 `open` / `doing`) |
96
+ | `--category` / `--tag` | 按分类(精确)/ 标签(包含)筛 |
97
+ | `--since` / `--until` | 按创建时间筛(只给日期含当天) |
98
+ | `--json` | 输出 JSON(`{任务号: 任务对象}`) |
99
+
100
+ 干什么:合并公共池 + 各人名下的任务,列出在办。**默认就是全量**,没有 `--all` 参数;收窄用 `--mine` / `--pool`。
101
+
102
+ 举例:「现在该做什么」→ `list --mine`;「有哪些没人认领的」→ `list --pool`。
103
+
104
+ ### show — 看一条任务
105
+
106
+ | 参数 | 含义 |
107
+ |---|---|
108
+ | `--id <任务号>` | 看哪条(必填;谁名下的都能看) |
109
+ | `--json` | 连过程文档全文一起给(人话模式只给路径) |
110
+
111
+ 干什么:拿任务 JSON + 过程文档路径 / 全文。改既有任务正文前,先用它拿路径。
112
+
113
+ 举例:「这个任务到哪一步了」→ `show --id <任务号> --json`。
114
+
115
+ ### history — 查已结案
116
+
117
+ | 参数 | 含义 |
118
+ |---|---|
119
+ | `--owner <邮箱>` / `--mine` | 按 owner 筛 |
120
+ | `--category` / `--tag` | 按分类 / 标签筛 |
121
+ | `--since` / `--until` | 按**结案时间**筛(只给日期含当天) |
122
+ | `--months N` | 最近 N 个自然月(与 `--since` / `--until` **互斥**,同传直接报错) |
123
+ | `--limit N` | 最近 N 条 |
124
+ | `--count-only` | 只输出 `{"count","capped"}`(与 `--json` 互斥) |
125
+ | `--json` | JSON 输出 |
126
+
127
+ 干什么:按结案时间倒序排列,每条一行,只列结案时间、负责人、标题,其他都不在表格里;要摘要 / 分类 / 标签 / 完整时间加 `--json`。不给时间参数 = 最近 3 个自然月;最多 13 个月,超了直接报错。
128
+
129
+ 举例:「上周做过什么」→ `history --since <上周一日期>`;「今年都结掉哪些」→ `history --months 12`(超过 13 个月要分段查)。
130
+
131
+ ## 怎么调用
53
132
 
54
133
  ```bash
55
134
  python3 <本 SKILL.md 所在目录>/scripts/progress.py <子命令> --repo <当前工作区>
56
135
  ```
57
136
 
58
- 子命令:`init` `new` `claim` `set` `log` `close` `list` `history` `show` `tags` `validate`。
59
- 参数细节一律看 `<子命令> --help`(不要凭记忆编参数)。
60
- 写类命令返回 worklog 路径 + 全文;`list` / `history` 只返回摘要,不吐正文。
137
+ - 定位项目:`--repo <目录>` 给了就用;不给就从当前目录逐级向上找第一个含 `ledger/` 的目录。
138
+ - `--no-sync`(放在子命令**前**):用户明确要求「先别同步」时才用;之后自己 `git add ledger && commit && push`。
139
+ - `--json` 只对只读命令(`list` / `show` / `history` / `validate`)有意义;写命令不接收 `--json`,传了是用法错。`--json` 里的时间字段是 UTC,人话输出是本地时间。
140
+ - 命令回执只用来确认生效;任务状态以 `show` / `list` 为准。
61
141
 
62
- ## 铁律
142
+ ## 任务生命周期
63
143
 
64
- - **状态只有 `open` / `doing`**;`done` 只能由 `close` 产生。**没有 `blocked` 状态**:逾期 = `started` 满 14 天、停滞 = `updated` 满 3 天、积压 = `created` 满 30 天且仍 `open`,都由看板按时间算,`progress.json` 里不存、不手改;卡在哪写进正文。
65
- - **`log` 就是刷新 `updated` 的动作**:该记不记,任务会被看板标成停滞。
66
- - **owner = 当前 `git config user.name`**,不能由外部传入;读不到就报错(先让用户配 git)。**只能动自己名下**的任务(`open` 的先 `claim`),不是你的直接拒绝 —— 不要绕过脚本改 JSON。
67
- - **换人只能「释放 → 认领」**:skill 不提供交接,随便写的名字都是假的。
68
- - **「执行记录」禁手改**:只由脚本按 `new / claim / set / release / log / close` 追加,只增不改;手写=伪造时间线,且不刷新 `updated`。
69
- - **改正文必配一条日志**:只要动了 worklog 的正文(改一句、补一节、改标题、修错字都算),**必须立刻跑一次 `log`**。没有对应日志的正文改动 = 这轮没做完 —— 时间线上会留下你改过、但没人知道为什么改的空洞。
70
- - **升级前建的老 worklog 没有这一节**:不用你补,脚本第一次记时自动在文末补一节;文档丢失时 `log` 报错(`updated` 已刷新),用 `show` 查路径,**不要手写**。
71
- - **旧数据里的 `blocked`**:读侧当进行中;`list --status blocked` 可捞出,用 `set --status doing` 归位。
144
+ 用户要「做某件事」时按这条线走。
72
145
 
73
- 细节见 `references/state-model.md`。
146
+ 1. **建(只建,不认领)—— 默认**:「新建一个任务」「新建个任务,我们来干 X」「新建个任务,我需要处理 Y」→ `new --title "…"`。落公共池、待认领。
147
+ 2. **建并认领 —— 仅限明确说法**:用户明确说「新建一个任务**并开始做 / 并执行**」这类带着「现在就开始」的话 → `new --title "…" --self`。直接归自己名下、「进行中」。**除这种明确说法,其他一律按第 1 条只建** —— 别替用户决定他要开始做;拿不定,问一句。
148
+ 3. **找已有的**:用户说「我们来做 X」→ 先 `list --mine` 找自己名下的,在做的直接接着做;没有 → `list --pool` 里找,找到先问用户:「X 还没认领,认领它吗?」→ 用户点头再 `claim`;哪儿都没有 → 按第 1/2 条的判定规则建。
149
+ 4. **认领**:`claim --id <任务号>` —— 认到自己名下,状态即「进行中」。
150
+ 5. **推进**:改 worklog 前五节 → 按「过程文档」节的收工三步记 `log`。卡住也 `log`(写清卡在哪,状态不动);「先放一放」同理 —— 是暂停,不是释放。
151
+ 6. **交付待验收**:任务留「进行中」,「待办」写「待用户验收」,「下一步」写清验收看什么;照收工三步记一条 `log --note "已交付待验收:…"`。
152
+ 7. **释放**:仅当用户明确说「退回去 / 释放掉」→ `set --id <任务号> --owner ""`。任务回公共池,别人可认领。
153
+ 8. **结案**:仅当用户明确说「把这个任务结束掉 / close 掉」→ `close --id <任务号> --summary "…"`;说得含糊(「做完了」「验收通过」)先反问「是要结束这个任务吗?」。收尾顺序:**先补完正文 + 记 log,最后才 close** —— 关了就不能再写。
154
+ 9. **查询**:在办 `list` / 单条 `show` / 已结案 `history`(默认只近 3 个自然月,更早的要 `--months` / `--since`)。
74
155
 
75
156
  ## 过程文档
76
157
 
77
- 1. **建档**:`new` 按模板建六节骨架并把路径写进状态表。
78
- 2. **推进**:你直接编辑前五节,标题不许改名;**每改一轮正文就配一条日志**——同一次编辑动作里连改多处只记一条,改完立刻 `log --note "这轮做了什么"`。
79
- 3. **交付(待验收)**:任务仍留 `doing`,「待办」写「待用户验收」,「下一步」写清验收该看什么;这轮**照样要走收工三步**。结论只写可验证事实,评价等用户验收。
80
- 4. **封卷**:`close` 打封卷标记,此后不再改;文档靠 `history` 给的回链找回。
158
+ `new` 按模板建好六节骨架,路径由 `show` 给出;前五节是本 skill 唯一允许手写的内容。
81
159
 
82
- 细节见 `references/worklog.md`。
160
+ | 节 | 写什么 |
161
+ |---|---|
162
+ | 背景 | 为什么做:触发它的原话 / 现象 / 链接 |
163
+ | 待办 | 还没做的、没验证的、等别人给东西的 |
164
+ | 下一步 | 下一个**具体动作**(文件:行号 级别),不写「继续推进」 |
165
+ | 过程 | 踩坑与证据:带 revision + `文件:行号` 或符号名 |
166
+ | 结论 | 做成了什么、留了什么坑;只写可验证事实,评价等用户验收 |
167
+ | 执行记录 | 脚本维护,**禁止手写**(见「手写边界」) |
83
168
 
84
- ## 每次收工必做(「收工」= 这一轮对用户有可见产出)
169
+ 规则:
85
170
 
86
- 1. 改正文:这轮变化的事实都落笔,「下一步」写具体动作,不写「继续推进」。
87
- 2. 跑 `log`:**这一轮只要改过正文就必须记**(一轮至少一条);正文没变也能记一条推进,但要同时重写「下一步」。
88
- 3. 回读末行(`tail -n 3 <路径>` 或 `show --id`):时间 = 现在、说明 = 这轮的事。
171
+ - 「执行记录」节名一个字都别动;老文档缺这一节也不用补。
172
+ - 过程文档找不到时 `log` 只提示不失败;用 `show` 查路径,不要手写。
173
+ - 头部只有创建时间 / 创建人、封卷标记、分类 / 标签行 —— **状态与归属以台账数据为准,别从头部读**。
174
+ - 执行记录行格式 `- 本地时间 · 类型 · @谁 · 说明`,`@谁` 是这次动手的人、不是任务现归属;只追加、不改旧行。行首「类型」是脚本内部动作名(会见到 `release`,它就是 `set --owner ""`);认不出就别当成新命令,按 `--help` 查。
175
+ - 只改某条任务的正文:`show --id <任务号>` 拿路径直接改,不另建 md;已结案的用 `history --months 12`(或 `--since`)找回链接——默认只查近 3 个月,结案久了的要显式放大窗口;只读不改。
89
176
 
90
- 交付前必须走完这三步;不走,这轮等于没发生,看板还会标停滞。
177
+ ### 收工三步(「收工」= 这一轮对用户有可见产出)
91
178
 
92
- **什么算一个节点**:明天你自己想不起来、或换个人接手会看不出的事,就记一条;一次状态/结论变化对应一条,不对应一次工具调用。
93
- `--note` 一句一条、约 60 字、含命令 / `文件:行号` / 符号名 / 结论之一。
94
- 不记:读文件、跑 `list`、改错别字、依赖锁文件变更。
179
+ 1. 改正文:这轮变化的事实都落笔,「下一步」写具体动作。
180
+ 2. 跑 `log`:这一轮只要改过正文就必须记(一轮至少一条;纪律见下文)。正文没变也能记一条推进,但要同时重写「下一步」。
181
+ 3. 回读末行(`tail -n 3 <路径>`):说明 = 这轮的事。执行记录行的时间是本机本地时间,别以为没记上。
95
182
 
96
- 细节与正反例见 `references/log-note.md`。
183
+ **什么算一个节点**:明天自己想不起来、或换个人接手会看不出的事,就记一条;一次状态 / 结论变化对应一条,不对应一次工具调用。拿不准够不够格、`--note` 不会写 → 见 `references/log-note.md`。
97
184
 
98
- ## 分类与标签
185
+ ## 纪律
99
186
 
100
- `new` 时自行总结:`--category` 答「是什么类型」(单值,≤4 字,吃不准写「其他」);`--tags` 答「涉及什么」(0~5 个,写不出就留空)。
101
- 口径错开:tags 不许写 category 的同义词。统计只认 category,查询用 tags(包含匹配)。
187
+ ### 数据完整性(脚本管不了的,违反了数据就脏)
102
188
 
103
- 细节见 `references/taxonomy.md`。
189
+ - **执行记录禁手改**:只由脚本按 `new / claim / set / release / log / close` 追加,只增不改。
190
+ - **改正文必配一条日志**:动了 worklog 的正文(改一句、补一节、改标题、修错字都算)就必须立刻跑一次 `log`。
191
+ - **换人只能「释放 → 认领」**:`set --owner ""` 放回公共池,对方自己 `claim`;不许替别人挂名字。`set --owner <别人>`(预留转接通道,agent 一律不用)。
192
+ - **身份由脚本自取,agent 全程不传 owner**:查自己用 `--mine`,只有查别人才传对方邮箱(`list --owner <邮箱>`);释放传的是空串 `--owner ""`,不是身份。看到「读不到 git 身份」提示 ⇒ 让用户配 git,否则任务记到兜底身份名下。
104
193
 
105
- ## 写操作红线
194
+ ### 人类授权(跑之前问不问)
195
+
196
+ 项目没有 `ledger/` ⇒ 先问「要不要建个台账记这活?」,不许自建。用户同意 ⇒ 直接跑第一条写命令,且**必须带 `--repo <项目根>`**:不带时脚本只从当前目录逐级往上找第一个含 `ledger/` 的目录,一个都没有就退 1 报「找不到台账」,绝不就地建;台账由这条写命令顺带建出来,没有 `init` 命令。之后可以不带 `--repo`,但查找是**逐级往上**的 —— 在本项目的子目录里跑可能命中上层项目的台账,拿不准就一直带 `--repo <项目根>`。
106
197
 
107
198
  | 命令 | 档位 | 要求 |
108
199
  |---|---|---|
109
- | `init` / `new` / `claim` / `set` | 动手类 | 执行前把完整参数复述给用户并取得确认 |
110
- | `log` | 免确认 | 本任务的推进 / 卡点 / 交付记录直接跑,跑完一句话交代「已记执行记录:…」;要替用户下结论、或替别人记,先问 |
111
- | `close` | 独立授权 | 只认用户明确的验收 / 结案 / 放弃指令;**agent 自判「干完了」不算** —— 那是交付,停在 `doing` 等用户回话 |
112
- | `tags --rename` | 批量写 | 先 `tags --all`,把影响条数与任务号报给用户,确认后再改 |
113
- | `list` / `show` / `history` / `validate` / `tags --all` | 只读 | 直接跑 |
114
-
115
- ## 出错即停
200
+ | `new` / `claim` / `set` | 动手类 | 执行前把完整参数复述给用户并取得确认 |
201
+ | `log` | 免确认 | 本任务的推进 / 卡点 / 交付记录直接跑,跑完一句话交代「已记执行记录:…」;要替用户下结论,先问(任务不在自己名下会直接被拒) |
202
+ | `close` | 独立授权 | 仅认明确说「结束掉 / close 掉」(完整判定见生命周期第 8 条);说得含糊必须反问「是要结束这个任务吗?」;**agent 自判「干完了」不算** |
203
+ | `list` / `show` / `history` / `validate` | 只读 | 直接跑 |
116
204
 
117
- 非 0 退出就停手、原样报告,**不要绕过脚本手改 `progress.json` 或历史层**。
118
- **退出码 0 不等于没事**:写命令之后的同步(commit / push)失败仍返回 0,原因只写在输出里。写命令跑完必看输出,出现 `提示:` / `错误:` / `警告:` 就先用一句话说清「发生了什么 + 你要做什么」,再附原文关键行,按 `references/troubleshooting.md` 对应条目给步骤;纯告知类(如已用 `--no-verify` 提交)一句话带过。只读命令只有 `错误:` 才需要转述。
119
- 并发冲突(文件被改动)重跑一次即可,不要用 `git pull` / `rebase` 去「解决」。
120
- 写前会**定向取最新**:只刷新 `ledger/progress.json` 与 `ledger/history/`,`worklog/` 里已有的正文一个字都不动;
121
- 本地有未推送的台账提交、未提交改动或未入库的同名文件时会中止 —— 按提示先提交 / 推送,或加 `--no-sync` 继续本地写。
122
- 同一仓库里写命令**排队**执行(最多等 60 秒),并发时不要重试轰炸,等前一个跑完再重跑。
205
+ ### 故障处置(跑之后出事怎么办)
123
206
 
124
- 细节见 `references/troubleshooting.md`。
207
+ - **动作阶段失败(输出以 `错误:` 开头)= 该命令没生效**:不挡主任务 —— 继续手里的活,收尾时汇报「没记上,原因 …」;不绕过脚本手改文件。
208
+ - **退出码 0 也要看输出**:出现 `提示:` / `错误:` / `警告:` 就先用一句话说清「发生了什么 + 下一步做什么」,再按 `references/troubleshooting.md` 给步骤;纯告知类一句话带过。只读命令只有 `错误:` 才需要转述。
209
+ - **两类不是故障的退出码**:`validate` 查出问题时退出码 1,照实转述清单;提交阶段失败 ⇒ 文件已经写下去、只差进 git,让用户先提交再重跑,别说「没记上」。
210
+ - **并发冲突**(文件被改动、抢不到锁)重跑一次即可;台账同步一律交给脚本,不要自己 `git pull` / `rebase` 去「解决」(脚本明说不代劳的几种除外,见 troubleshooting)。
211
+ - 同一仓库里写命令排队执行,等前一个跑完再重跑。
125
212
 
126
213
  ## references(按需读,别全读)
127
214
 
128
215
  | 何时读 | 文件 |
129
216
  |---|---|
130
- | 要传 `--created` / `--finished` 补录时间、看到旧 `blocked`、答「停太久」要解释口径 | `references/state-model.md` |
131
- | 填正文前、补老任务文档、`log` 报错找不到文档 | `references/worklog.md` |
132
- | 拿不准一条记录够不够格、`--note` 怎么写 | `references/log-note.md` |
133
- | 写分类/标签、用户说标签太乱要归并 | `references/taxonomy.md` |
134
- | 任何非 0 退出、退出码 0 但有 `提示:` / `错误:`、并发冲突、`validate` 报错 | `references/troubleshooting.md` |
217
+ | 任何非 0 退出、退出码 0 但有 `提示:` / `错误:` / `警告:`、并发冲突、`validate` 报错 | `references/troubleshooting.md` |
218
+ | 传 `--created` / `--finished` 补录时间、看到旧 `blocked`、看 `--json` 里的时间字段、查别人时 owner 匹配异常、看 history 列义 / 时间窗口口径 / 旧格式行 | `references/state-model.md` |
219
+ | 拿不准一条记录够不够格、`--note` 不会写 | `references/log-note.md` |