scrum-skills 0.1.2 → 0.2.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.
Files changed (55) hide show
  1. package/.agents/skills/scrum-planning/SKILL.md +10 -4
  2. package/.agents/skills/scrum-planning/references/schema.md +141 -60
  3. package/.agents/skills/scrum-report/SKILL.md +8 -4
  4. package/.agents/skills/scrum-sprint/SKILL.md +8 -3
  5. package/.agents/skills/scrum-tdd/SKILL.md +3 -3
  6. package/README.md +132 -0
  7. package/assets/board/200.html +1 -0
  8. package/assets/board/404.html +1 -0
  9. package/assets/board/_nuxt/BNG0e--z.js +6 -0
  10. package/assets/board/_nuxt/BWaQPvUU.js +8 -0
  11. package/assets/board/_nuxt/BcDeF-Nj.js +1 -0
  12. package/assets/board/_nuxt/BeTHElHy.js +1 -0
  13. package/assets/board/_nuxt/BrhpXuqy.js +1 -0
  14. package/assets/board/_nuxt/Brv_Bdja.js +3 -0
  15. package/assets/board/_nuxt/C218H_dA.js +1 -0
  16. package/assets/board/_nuxt/C37hh6-M.js +1 -0
  17. package/assets/board/_nuxt/C6_z9Ljo.js +1 -0
  18. package/assets/board/_nuxt/CNsYxQaQ.js +1 -0
  19. package/assets/board/_nuxt/Cg4fvkkC.js +4 -0
  20. package/assets/board/_nuxt/Ci-XR_iv.js +1 -0
  21. package/assets/board/_nuxt/Cxemkb8I.js +3 -0
  22. package/assets/board/_nuxt/D1zk137d.js +1 -0
  23. package/assets/board/_nuxt/D8i1JTd1.js +1 -0
  24. package/assets/board/_nuxt/DK3Fl9T5.js +1 -0
  25. package/assets/board/_nuxt/DVUil5cj.js +1 -0
  26. package/assets/board/_nuxt/DW7rSQ02.js +1 -0
  27. package/assets/board/_nuxt/DbghXjRj.js +1 -0
  28. package/assets/board/_nuxt/DcGinDT7.js +6 -0
  29. package/assets/board/_nuxt/DhgUnnc1.js +16 -0
  30. package/assets/board/_nuxt/DqkHw_T9.js +1 -0
  31. package/assets/board/_nuxt/DuWpPgcw.js +3 -0
  32. package/assets/board/_nuxt/OHMTu69O.js +1 -0
  33. package/assets/board/_nuxt/W_UkaXSY.js +1 -0
  34. package/assets/board/_nuxt/_id_.IxcmgCc3.css +1 -0
  35. package/assets/board/_nuxt/builds/latest.json +1 -0
  36. package/assets/board/_nuxt/builds/meta/cf3421e0-2439-4091-aeea-10c06027154f.json +1 -0
  37. package/assets/board/_nuxt/burndown.DSciF97B.css +1 -0
  38. package/assets/board/_nuxt/entry.DEq3ipbJ.css +2 -0
  39. package/assets/board/_nuxt/epics.jbQSHA_o.css +1 -0
  40. package/assets/board/_nuxt/error-404.BFmXOnCT.css +1 -0
  41. package/assets/board/_nuxt/error-500.BZ-DdjQ6.css +1 -0
  42. package/assets/board/_nuxt/gantt.BZpeqgtE.css +1 -0
  43. package/assets/board/_nuxt/milestones.DqyGYjt4.css +1 -0
  44. package/assets/board/_nuxt/pages.D1M7qr1l.css +1 -0
  45. package/assets/board/burndown/index.html +1 -0
  46. package/assets/board/epics/index.html +1 -0
  47. package/assets/board/gantt/index.html +1 -0
  48. package/assets/board/index.html +1 -0
  49. package/assets/board/milestones/index.html +1 -0
  50. package/bin/scrum-skills.mjs +17 -5
  51. package/docs/board.png +0 -0
  52. package/package.json +24 -3
  53. package/templates/AGENTS.md +25 -11
  54. package/tools/serve.mjs +88 -143
  55. package/tools/validate.mjs +319 -109
@@ -11,7 +11,7 @@ description: 将用户与 AI 的需求对话约束为结构化敏捷数据(Epi
11
11
 
12
12
  ## 核心纪律
13
13
 
14
- 1. **禁止只聊天**。凡是确认要做的事,必须落成 `agile/backlog/` 下的 JSON 文件(schema 见 `references/schema.md`)。对话中的口头结论不算数,文件才算数。
14
+ 1. **禁止只聊天**。凡是确认要做的事,必须落成 `agile/backlog.json`(迭代/里程碑落 `agile/sprints.json`,日志落 `agile/journal.json`;schema 见 `references/schema.md`)。对话中的口头结论不算数,文件才算数。
15
15
  2. **禁止凭空拆解**。写 story 前先走「澄清」流程(见下节),澄清结果写进
16
16
  `narrative` 和 `acceptance`,不许留在对话记录里。
17
17
  3. **数据是唯一事实来源**。后续实施只读文件不读对话记忆。AI 每次接手必须先读 `agile/` 下相关 JSON,再决定下一步。
@@ -31,13 +31,17 @@ description: 将用户与 AI 的需求对话约束为结构化敏捷数据(Epi
31
31
  1. **定位层级**:判断这是 Epic(多迭代的大目标)还是 Story(一个迭代内可交付的用户价值)。拿不准就先建 Epic,Story 留空壳。
32
32
  2. **写 Story**:
33
33
  - `narrative` 必须是「作为 X,我想要 Y,以便 Z」三段式
34
- - `acceptance` 至少 1 条,用 given/when/then 格式,必须可验证(能写测试或能演示)
34
+ - `type`:`feature` / `bug` / `debt` / `spike`;`bug` 必须同时写 `bug` 三件套(severity / environment / steps),说不出复现步骤的就还不是 bug
35
+ - `priority`(P0~P3)+ `value`:`value / points` 就是 WSJF,用来回答「下一个迭代先做谁」
36
+ - `acceptance` 至少 1 条,用 given/when/then 格式,必须可验证;每条都要写 `verifyBy` 指向覆盖它的 task(否则验收只是口号)
35
37
  - `points` 按斐波那契估(1/2/3/5/8),不确定就标 8 并在下次规划重估
38
+ - 有前置故事就写 `dependsOn`(不许成环);当下被卡住就写 `blocked: { reason, since }`,不要只在对话里提
36
39
  3. **拆 Task**:每个 story 拆成 test/impl/refactor/chore 型任务:
37
40
  - **test 型任务先行**:每条可自动验证的 acceptance 至少对应一个 test 型 task
38
41
  - test 与 impl 分开拆,不许一个 task 既写测试又写实现
39
- - 每个 task 必须有 `journal` 字段指向日志文件(先建空壳不写内容)
40
- 4. **编号**:取当前最大编号 +1,E-001/S-001 格式,不复用已删除编号。
42
+ - 每个 task 在 `agile/journal.json` 的 `journals` 里占一条 `entries: []` 的空壳记录
43
+ - 故事若要在甘特图上显示计划排期,补 `schedule: { start, end }`(可选,不填就落「未排期」)
44
+ 4. **编号**:取当前最大编号 +1,`E-001` / `S-001` / `M-001` 格式,不复用已删除编号;迭代 id 另见 `references/schema.md` 的「迭代编号规则」。
41
45
  5. **落库后**:向用户复述 story id 与验收标准清单,运行 `node tools/validate.mjs` 确认通过。
42
46
 
43
47
  ## 输出模板(对话中的回复结构)
@@ -53,3 +57,5 @@ description: 将用户与 AI 的需求对话约束为结构化敏捷数据(Epi
53
57
  - acceptance 写「功能正常」「体验良好」这类不可验证的空话
54
58
  - 把 test 和 impl 塞进同一个 task
55
59
  - 修改 story 时不更新 acceptance 却改了行为(验收标准必须与实现同步演进)
60
+ - 只写 `priority` 不写 `value`(或反过来)—— 没有 WSJF 就没法回答「先做谁」
61
+ - 用 narrative 描述依赖/阻塞,而不写 `dependsOn` / `blocked`(看板和甘特图读不到,等于没记)
@@ -1,93 +1,174 @@
1
- # 敏捷数据 Schema 规范(唯一事实来源)
1
+ # 敏捷数据 Schema(v3 · 三文件结构)
2
2
 
3
- 所有文件为 UTF-8 JSON,2 空格缩进,末尾换行。禁止出现 schema 未定义的字段。
4
- 路径与命名固定:`agile/backlog/epics/E-<3位>.json`、`agile/backlog/stories/S-<3位>.json`、`agile/sprints/<id>.json`、`agile/journal/<storyId>-<taskId>.json`。
3
+ `agile/` 下**只有三个文件**,全部 UTF-8 JSON、2 空格缩进、末尾换行。
5
4
 
6
- ## Epic(敏捷史诗)
5
+ | 文件 | 装什么 |
6
+ |---|---|
7
+ | `agile/backlog.json` | 史诗 epics(含量化目标 keyResults)+ 用户故事 stories(内联 tasks) |
8
+ | `agile/sprints.json` | 迭代 sprints + 里程碑 milestones(MVP 节点是里程碑的一种) |
9
+ | `agile/journal.json` | TDD 实施日志 journals(一个 task 一条,内联 entries) |
7
10
 
8
- ```json
9
- {
10
- "id": "E-001",
11
- "title": "用户认证",
12
- "goal": "一句话说明这个史诗完成后用户获得了什么",
13
- "status": "draft | active | done | cancelled",
14
- "stories": ["S-001"],
15
- "created": "2026-10-25"
16
- }
17
- ```
11
+ > 三个文件都必须带 `"schemaVersion": 3`。v2 及更早的散文件结构不再兼容,校验器发现 `agile/backlog/epics/`、`agile/backlog/stories/`、`agile/sprints/`、`agile/journal/` 里还有 JSON 会直接报错。
18
12
 
19
- ## Story(用户故事)
13
+ ## 1. backlog.json
20
14
 
21
15
  ```json
22
16
  {
23
- "id": "S-001",
24
- "epicId": "E-001",
25
- "title": "邮箱密码登录",
26
- "narrative": "作为<角色>,我想要<能力>,以便<价值>",
27
- "acceptance": [
28
- { "given": "已注册用户", "when": "输入正确邮箱密码提交", "then": "建立会话并跳转首页" }
29
- ],
30
- "tasks": [
17
+ "schemaVersion": 3,
18
+ "epics": [
31
19
  {
32
- "id": "S-001-T1",
33
- "title": "为登录接口写失败测试",
34
- "type": "test | impl | refactor | chore",
35
- "status": "todo | red | green | refactored | done",
36
- "files": [],
37
- "journal": "agile/journal/S-001-T1.json"
20
+ "id": "E-001",
21
+ "title": "用户认证与工作空间",
22
+ "goal": "一句话说明这个史诗完成后用户获得了什么",
23
+ "status": "draft | active | done | cancelled",
24
+ "keyResults": [
25
+ { "id": "E-001-KR1", "text": "新成员从收到邀请到能登录用时", "unit": "分钟", "target": 2, "current": 1.5 }
26
+ ],
27
+ "stories": ["S-001", "S-002"],
28
+ "created": "2026-08-24"
38
29
  }
39
30
  ],
40
- "points": 3,
41
- "status": "draft | ready | in-progress | review | done",
42
- "sprintId": null,
43
- "created": "2026-10-25"
31
+ "stories": [
32
+ {
33
+ "id": "S-001",
34
+ "epicId": "E-001",
35
+ "title": "邮箱密码登录",
36
+ "narrative": "作为<角色>,我想要<能力>,以便<价值>",
37
+ "type": "feature | bug | debt | spike",
38
+ "priority": "P0 | P1 | P2 | P3",
39
+ "value": 13,
40
+ "bug": {
41
+ "severity": "blocker | major | minor | trivial",
42
+ "environment": "Chrome 120 / Windows 11,看板页四列布局",
43
+ "steps": "1. …;2. …;3. …"
44
+ },
45
+ "acceptance": [
46
+ { "given": "已注册用户", "when": "输入正确邮箱密码提交", "then": "下发会话 cookie 并跳转首页", "verifyBy": ["S-001-T1"] }
47
+ ],
48
+ "points": 5,
49
+ "status": "draft | ready | in-progress | review | done | cancelled",
50
+ "sprintId": "R1-S1",
51
+ "created": "2026-08-24",
52
+ "schedule": { "start": "2026-08-31", "end": "2026-09-08" },
53
+ "dependsOn": ["S-004"],
54
+ "blocked": { "reason": "等产品确认是否要留审计日志", "since": "2026-10-21" },
55
+ "scopeChange": { "kind": "added-mid-sprint | split | expanded", "at": "2026-10-15", "reason": "客户临时插需求" },
56
+ "tasks": [
57
+ {
58
+ "id": "S-001-T1",
59
+ "title": "为登录接口写失败测试",
60
+ "type": "test | impl | refactor | chore",
61
+ "status": "todo | red | green | refactored | done",
62
+ "files": ["tests/auth/login.spec.ts"]
63
+ }
64
+ ]
65
+ }
66
+ ]
44
67
  }
45
68
  ```
46
69
 
47
- ## Sprint(迭代)
70
+ 字段说明:
71
+
72
+ - **`type`**:`feature` 功能 / `bug` 缺陷 / `debt` 技术债 / `spike` 调研。`bug` 必须同时给 `bug` 详情三件套(severity / environment / steps),否则校验报错。
73
+ - **`priority`**:P0 最高。数组顺序即 backlog 排序(rank),看板可再按优先级或 WSJF 重排。
74
+ - **`value` + `points`** → WSJF = value / points,用来决定「先做谁」;点数仍是成本口径,两者别混。
75
+ - **`acceptance[].verifyBy`**:这条验收由哪个 task 的测试覆盖(task id)。非 `draft` 状态没写只给 WARN,但它是「验收不是口号」的唯一凭据,建议必填。
76
+ - **`dependsOn`**:故事级依赖,必须存在、不能自依赖、**不能成环**(校验器做 DFS 检测)。
77
+ - **`blocked`**:当前阻塞的事实(原因 + 起始日期)。已 `done` 的故事不许带 `blocked`;处于迭代里还被阻塞会 WARN(站会必须处理)。
78
+ - **`scopeChange`**:范围变更标记。`added-mid-sprint` 迭代中途插入、`split` 拆分产生、`expanded` 范围扩大。有了它,燃尽图上那段平台期才不会被误读成「拖延」。
79
+ - **`schedule`** 可选,只给甘特图用(计划区间);实际区间由 `journal.json` 的记录日期推出来,不用手填。
80
+ - task 的 `id` 必须是 `<storyId>-T<n>`;日志集中在 `journal.json`,用 `taskId` 关联。
81
+
82
+ ## 2. sprints.json
48
83
 
49
84
  ```json
50
85
  {
51
- "id": "P01-S1",
52
- "name": "第 1 个迭代",
53
- "goal": "本迭代要交付什么",
54
- "start": "2026-10-26",
55
- "end": "2026-11-08",
56
- "stories": ["S-001"],
57
- "capacity": 20
86
+ "schemaVersion": 3,
87
+ "sprints": [
88
+ {
89
+ "id": "R1-S1",
90
+ "name": "第 1 个迭代(登录与邀请)",
91
+ "goal": "本迭代要交付什么",
92
+ "start": "2026-08-31",
93
+ "end": "2026-09-13",
94
+ "stories": ["S-001", "S-002"],
95
+ "capacity": 12
96
+ }
97
+ ],
98
+ "milestones": [
99
+ {
100
+ "id": "M-001",
101
+ "title": "MVP · 内测可登录",
102
+ "kind": "mvp | release | checkpoint",
103
+ "due": "2026-09-13",
104
+ "status": "planned | at-risk | reached | missed",
105
+ "sprintId": "R1-S1",
106
+ "criteria": "达成口径:怎样算这个节点到了",
107
+ "stories": ["S-001", "S-002"]
108
+ }
109
+ ]
58
110
  }
59
111
  ```
60
112
 
61
- ## Journal(TDD 实施日志,每 task 一篇)
113
+ - **MVP 节点就是 `kind: "mvp"` 的里程碑**,不另设实体。
114
+ - `status: "reached"` 时挂的故事必须全部 `done/cancelled`,否则校验报错。
115
+ - `due` 早于今天但状态仍是 `planned` → WARN。
116
+
117
+ ### 迭代编号规则(`sprints[].id`)
118
+
119
+ 格式:`R<发布周期>-S<期内冲刺号>`,例如 `R1-S1`、`R1-S2`、`R2-S1`。
120
+
121
+ - **`S<期内冲刺号>`** 是 Sprint 本体 —— Scrum 里的 Sprint(冲刺/迭代)就是它,在一个发布周期内从 1 开始连号、不跳号。
122
+ - **`R<发布周期>`** 是引用Release(发布周期/版本)这一层的分组:若干个冲刺归到一个发布窗口,和 `milestones`(尤其 `kind: "release"`)对齐。当前约定**一个发布周期 = 4 周 = 2 个两周冲刺**。
123
+ 它不是 Scrum 术语(Scrum 只有 Sprint),业界最接近的是 Release 或 SAFe 的 PI(Program Increment,通常 8~12 周、含 4 个开发冲刺 + 1 个 IP 冲刺)。**既然叫 Release 就按 4 周一个周期排,别套 PI 的节奏。**
124
+ - 周期号按时间递增(`R1`、`R2`…,不带前导零);同一周期内冲刺号不得重复;**一个周期建议不超过 2 个冲刺**。
125
+ - 小团队不需要发布周期这一层时,可以只用 `S-01`、`S-02` 纯序号(整段省略 `R` 前缀),但**同一个项目里不许两种风格混用**。
126
+ - **id 被 `story.sprintId`、`milestones[].sprintId` 引用,定了就别改**;确需重命名时两处引用同步改,改完跑 `validate`(引用完整性会兜住漏改)。
127
+
128
+ 以上规则由 `tools/validate.mjs` 强制:id 必须匹配 `R<n>-S<n>` 或 `S-<n>`、不许混用风格、同一周期内冲刺号必须从 1 连续、周期号与起始日期顺序要一致(后两条分别报错与警告)。
129
+
130
+ ## 3. journal.json
62
131
 
63
132
  ```json
64
133
  {
65
- "taskId": "S-001-T1",
66
- "storyId": "S-001",
67
- "entries": [
134
+ "schemaVersion": 3,
135
+ "journals": [
68
136
  {
69
- "phase": "red | green | refactor",
70
- "date": "2026-10-26",
71
- "note": "这一步做了什么、为什么",
72
- "files": ["src/auth/login.ts"],
73
- "testCommand": "pnpm test auth",
74
- "result": "fail: 1 failed, 0 passed | pass: 3 passed"
137
+ "taskId": "S-001-T1",
138
+ "storyId": "S-001",
139
+ "entries": [
140
+ {
141
+ "phase": "red | green | refactor",
142
+ "date": "2026-08-31",
143
+ "note": "这一步做了什么、为什么",
144
+ "files": ["tests/auth/login.spec.ts"],
145
+ "testCommand": "pnpm test auth/login",
146
+ "result": "fail: 3 failed, 0 passed — 404 Not Found"
147
+ }
148
+ ]
75
149
  }
76
150
  ]
77
151
  }
78
152
  ```
79
153
 
80
- ## 状态机(校验脚本强制)
154
+ ## 状态机(校验器强制)
81
155
 
82
156
  - story: `draft → ready → in-progress → review → done`(可回退,不可跳级;`cancelled` 例外)
83
- - task: `todo → red → green → refactored → done`(只许前进;test 型 task 从 `todo` 直达 `green` 后视情况跳 refactor)
157
+ - task: `todo → red → green → refactored → done`(只能前进;test 型可 `todo → green`)
84
158
  - epic: 无强制流转,但 `done` 要求其下所有 story 均 `done/cancelled`
159
+ - milestone: `planned → at-risk → reached / missed`
85
160
 
86
- ## 硬约束(校验脚本强制)
161
+ ## 硬约束(校验器强制 / 警告)
87
162
 
88
- 1. 所有 ID 引用必须存在且指向正确类型(epicId / sprintId / stories / journal)
89
- 2. task 状态为 `green/refactored/done` 时,journal 必须存在且含至少一条 `phase: "red"` 的失败记录和一条 `phase: "green"` 的通过记录
90
- 3. task 状态为 `done` 时,journal 最后一条 entry 的 `result` 必须是 `pass`
91
- 4. story 状态为 `done` 时,其所有 task 必须 `done`
92
- 5. story 进入 sprint(sprintId 非空)前必须为 `ready`(acceptance 非空且 ≥1 条)
93
- 6. ID 全局唯一且不可复用;文件名与内部 id 一致
163
+ 1. ID 全局唯一(epic / story / task / sprint / milestone 共用命名空间),task 命名 `<storyId>-T<n>`
164
+ 2. **双向引用一致**:`epic.stories` ↔ `story.epicId`、`sprint.stories` ↔ `story.sprintId`、`journal.taskId` ↔ task
165
+ 3. `ready` 及之后必须有验收标准;进 sprint 的故事必须有验收标准
166
+ 4. 验收标准的 `verifyBy` 必须指向**同一 story 的** task
167
+ 5. task 到 `green/refactored/done` 时,journal 必须存在且首条 `red` 的 result 以 `fail` 开头、`green` 以 `pass` 开头
168
+ 6. task 为 `done` 时,journal 末条 entry 的 `result` 必须 `pass`
169
+ 7. story 为 `done` 时,其所有 task 必须 `done`,且不许仍标着 `blocked`
170
+ 8. 同时只能有一个活跃 sprint(`start ≤ 今天 ≤ end`)
171
+ 9. `dependsOn` 必须存在、不能自依赖、不能成环
172
+ 10. `schedule.start ≤ schedule.end`;计划区间超出所属迭代只给 WARN
173
+ 11. sprint 承诺点数超过 `capacity` → WARN
174
+ 12. epic 没有 `keyResults` → WARN(史诗要有量化目标)
@@ -18,13 +18,17 @@ npx scrum-skills serve # 默认当前目录 http://localhost:4173
18
18
  npx scrum-skills serve . 8080 # 指定目录与端口
19
19
  ```
20
20
 
21
- server 读取 `agile/` 全量 JSON,纯内存聚合,不写文件。改了数据刷新页面即生效。
21
+ server 读取 `agile/` 三文件(backlog / sprints / journal),每次请求现取,不写文件。改了数据刷新页面即生效。
22
22
 
23
23
  ## 页面
24
24
 
25
- - `/` 看板:按 story 状态分列(draft/ready/in-progress/review/done),卡片显示 id、标题、点数、task 进度条
26
- - `/burndown` 燃尽图:当前活跃 sprint 的剩余点数曲线(无活跃 sprint 时提示)
27
- - `/story/S-001` 追溯链:acceptance → task → journal 每阶段(red/green/refactor)的完整记录
25
+ 渲染由 Nuxt 静态产物(`assets/board/`)负责,`tools/serve.mjs` 只提供 `/api/agile` 与静态托管,没有任何手写 HTML。
26
+
27
+ - `/` 看板:六列(草稿 / 就绪 / 进行中 / 评审 / 完成 / 已取消),可按史诗、里程碑筛选,可按优先级 / WSJF / 点数重排;卡片显示 id、类型(功能·缺陷·技术债·调研)、优先级、阻塞标记、范围变更标记、点数与 WSJF、task 进度、MVP 标记
28
+ - `/gantt` 甘特图:按迭代分带;浅色条是 `story.schedule` 计划区间,实心条是 journal 推出的真实执行区间;菱形是里程碑(MVP 琥珀色),红色虚线是今天;行内标出依赖数量与阻塞,图下列出依赖链与阻塞清单
29
+ - `/milestones` 里程碑 / MVP 节点:按 kind 分组(mvp / release / checkpoint),显示达成口径、挂的故事、进度与剩余天数
30
+ - `/burndown` 燃尽图:可选任意迭代;实线来自每个 task 最后一条 pass 的日期,虚线是理想线,逐日格子给出实际/理想剩余
31
+ - `/story/S-001` 追溯链:acceptance → task → journal 每阶段(red/green/refactor)的完整记录,含测试命令与产出文件
28
32
 
29
33
  ## 纪律
30
34
 
@@ -11,16 +11,19 @@ description: 管理 Sprint 迭代周期与 Story 状态流转,落库到 agile/
11
11
 
12
12
  ## 前置
13
13
 
14
- 先读 `agile/backlog/stories/` 全量与当前活跃 sprint,掌握真实状态。**状态以文件为准,对话记忆一律作废。**
14
+ 先读 `agile/backlog.json`(epics + stories)与 `agile/sprints.json`(sprints + milestones),掌握真实状态。**状态以文件为准,对话记忆一律作废。**
15
15
 
16
16
  ## 工作流
17
17
 
18
18
  ### 组建 Sprint
19
19
 
20
20
  1. 从 backlog 中挑 `ready` 状态的 story(不满足 ready 的先回 scrum-planning 补验收标准)
21
+ - 排序依据:`priority` 优先,同优先级比 WSJF(`value / points`)
22
+ - **依赖检查**:`dependsOn` 里的故事必须已完成,否则别排进本迭代;**阻塞检查**:带 `blocked` 的先解决阻塞再排
21
23
  2. 总点数不超过 `capacity`(默认 20,可和用户商量)
22
- 3. 写 `agile/sprints/<id>.json`(id 格式 `P<迭代序号>-S<期号>` 如 `P01-S1`),story 的 `sprintId` 同步更新
24
+ 3. 往 `agile/sprints.json` 的 `sprints` 数组里追加一条,story 的 `sprintId` 同步更新;**id 按 planning skill `references/schema.md` 的「迭代编号规则」生成**(`R<发布周期>-S<期内冲刺号>`,如 `R1-S1`),不许另发明格式
23
25
  4. 被选中的 story 状态改为 `in-progress`(或 sprint 启动时改)
26
+ 5. 与迭代绑定的里程碑写进同文件 `milestones`:MVP 节点用 `kind: "mvp"`,`due` 落在迭代结束日附近,`stories` 列出决定该节点是否达成的那几个故事
24
27
 
25
28
  ### 状态流转(严格按状态机,见 planning skill 的 schema.md)
26
29
 
@@ -34,7 +37,9 @@ description: 管理 Sprint 迭代周期与 Story 状态流转,落库到 agile/
34
37
 
35
38
  1. sprint 到期:未完成 story 回 backlog(`sprintId` 置 null,状态回 `ready`),完成项保持 `done`
36
39
  2. 生成回顾小结写入对话(做了什么/没做什么/为什么),不落文件除非用户要求
37
- 3. 建议用户运行 `node tools/serve.mjs` 查看燃尽图核对进度
40
+ 3. 里程碑到期没达成:状态改 `missed` 并写清差在哪几个故事;有风险但未到期改 `at-risk`;达成必须先把挂的故事推到 `done`
41
+ - 迭代中途插入的需求,必须给该 story 打 `scopeChange: { kind: "added-mid-sprint", at, reason }`;拆分出来的打 `split`。否则燃尽图上的偏差会被误读成团队拖延
42
+ 4. 建议用户运行 `node tools/serve.mjs` 看燃尽图(`/burndown`)与甘特图(`/gantt`)核对进度
38
43
 
39
44
  ## 硬约束
40
45
 
@@ -11,9 +11,9 @@ description: 以 red-green-refactor TDD 循环驱动任务实施,并把每一
11
11
 
12
12
  ## 前置
13
13
 
14
- 1. 读目标 story 的 JSON(验收标准 + task 列表)
14
+ 1. 从 `agile/backlog.json` 读目标 story(验收标准 + task 列表)
15
15
  2. 找到第一个非 `done` 的 task,确认其 `type`
16
- 3. 读该 task 的 journal(若有历史条目,从上次断点继续)
16
+ 3. 读 `agile/journal.json` 里该 task 的 entries(若有历史条目,从上次断点继续)
17
17
 
18
18
  ## Red-Green-Refactor 循环(每轮三阶段,顺序铁律)
19
19
 
@@ -55,7 +55,7 @@ description: 以 red-green-refactor TDD 循环驱动任务实施,并把每一
55
55
 
56
56
  ## Journal 纪律
57
57
 
58
- - 每个 task 一篇 `agile/journal/<storyId>-<taskId>.json`,**每次状态推进必须当场追加 entry**,不许攒到最后补
58
+ - 每个 task 一条记录,放在 `agile/journal.json` 的 `journals` 数组里(按 `taskId` 找),**每次状态推进必须当场追加 entry**,不许攒到最后补
59
59
  - note 写「为什么」不写「什么」(文件名 git log 里都有)
60
60
  - 中断(用户喊停/上下文不够):journal 追加一条 note 说明断点在哪,task 状态留在当前阶段
61
61
 
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # scrum-skills
2
+
3
+ 结构化的敏捷数据 + TDD 纪律 + 开箱就能看的看板,给「和 AI 一起做项目」这件事用。
4
+
5
+ AI 只负责把需求、任务、实施过程写成**结构化 JSON**,人打开浏览器就能看到看板、甘特图、里程碑、燃尽图和每个任务的 TDD 追溯链。数据是唯一事实来源,对话记忆不作数。
6
+
7
+ ![敏捷看板](docs/board.png)
8
+
9
+ ## 为什么
10
+
11
+ - **AI 写代码很快,但「做到哪了」全靠人问** → 每个故事/任务的状态、实施日志都落在 `agile/` 里,随时可查
12
+ - **TDD 靠自觉,容易悄悄跳过** → 校验器强制「先有失败的测试,才有实现」:task 过了 red 阶段,日志里必须有一条 `fail` 记录和一条 `pass` 记录
13
+ - **看板工具要么太重、要么数据锁死** → 三个 JSON 文件 + 一个零依赖 server,数据在你自己仓库里,`git diff` 就能审
14
+
15
+ ## 快速开始
16
+
17
+ ```bash
18
+ # 1. 在任意项目里初始化(生成 AGENTS.md、四个 skill、数据骨架)
19
+ npx scrum-skills init .
20
+
21
+ # 2. 让 AI 读 AGENTS.md,用 scrum-planning 建第一个 story
22
+ # (Claude Code / Cursor / CodeBuddy 等都会读这个文件)
23
+
24
+ # 3. 校验数据
25
+ npx scrum-skills validate
26
+
27
+ # 4. 打开看板
28
+ npx scrum-skills serve # → http://localhost:4173
29
+ ```
30
+
31
+ `init` 会建出 `agile/` 的三个文件骨架,并把四个 skill 装进 `.agents/skills/`:
32
+
33
+ | skill | 干什么 |
34
+ |---|---|
35
+ | `scrum-planning` | 需求澄清 → 写史诗/故事/验收标准/拆任务 |
36
+ | `scrum-sprint` | 排期、组建迭代、状态流转、里程碑、收尾 |
37
+ | `scrum-tdd` | red → green → refactor 循环 + 过程落库 |
38
+ | `scrum-report` | 看板 / 甘特 / 里程碑 / 燃尽 / 追溯链 |
39
+
40
+ ## 命令
41
+
42
+ | 命令 | 说明 |
43
+ |---|---|
44
+ | `scrum-skills init [dir] [--force]` | 初始化(已有 `AGENTS.md` 时拒绝,`--force` 备份后覆盖) |
45
+ | `scrum-skills update [dir] [--dry-run]` | 只刷新框架文件(skill / AGENTS.md / 校验器),**绝不碰 `agile/` 数据**,覆盖前备份 `*.bak` |
46
+ | `scrum-skills validate [dir]` | 校验数据(引用完整性 / 状态机 / TDD 纪律 / 里程碑 / 依赖无环) |
47
+ | `scrum-skills serve [dir] [port]` | 起看板(默认当前目录,端口 4173),**校验不通过时拒绝出报表** |
48
+
49
+ ## 数据长什么样
50
+
51
+ `agile/` 下只有三个文件:
52
+
53
+ | 文件 | 内容 |
54
+ |---|---|
55
+ | `agile/backlog.json` | 史诗 `epics`(含量化目标 `keyResults`)+ 故事 `stories`(内联 `tasks`) |
56
+ | `agile/sprints.json` | 迭代 `sprints` + 里程碑 `milestones`(MVP 节点 = `kind: "mvp"`) |
57
+ | `agile/journal.json` | 每个任务一条 TDD 日志 `journals`(内联 `entries`) |
58
+
59
+ ```jsonc
60
+ // 一条故事(节选)
61
+ {
62
+ "id": "S-017",
63
+ "type": "bug", // feature | bug | debt | spike
64
+ "priority": "P1", // P0~P3
65
+ "value": 8, // WSJF = value / points
66
+ "bug": { // type=bug 时必填三件套
67
+ "severity": "major",
68
+ "environment": "Chrome 120 / Windows 11",
69
+ "steps": "1. 勾选子任务;2. 返回看板;3. 拖动卡片 —— 进度条仍是旧值"
70
+ },
71
+ "acceptance": [
72
+ { "given": "…", "when": "…", "then": "…", "verifyBy": ["S-017-T1"] }
73
+ ],
74
+ "points": 2,
75
+ "status": "ready",
76
+ "sprintId": null,
77
+ "schedule": { "start": "2026-10-20", "end": "2026-10-23" }, // 甘特图的计划条
78
+ "dependsOn": ["S-004"], // 依赖,必须无环
79
+ "blocked": { "reason": "等复现环境确认", "since": "2026-10-22" },
80
+ "scopeChange": { "kind": "added-mid-sprint", "at": "2026-10-15", "reason": "客户临时插需求" },
81
+ "tasks": [
82
+ { "id": "S-017-T1", "title": "写复现缺陷的失败测试", "type": "test", "status": "todo", "files": [] }
83
+ ]
84
+ }
85
+ ```
86
+
87
+ 迭代 id 形如 `R1-S1`:`R<发布周期>`(一个发布周期 = 4 周 = 2 个冲刺)× `S<期内冲刺号>`;小团队也可以只用 `S-01` 纯序号,但同一项目不许混用。
88
+
89
+ ## 看板有什么
90
+
91
+ | 页面 | 内容 |
92
+ |---|---|
93
+ | `/` 看板 | 六列(草稿/就绪/进行中/评审/完成/已取消),按史诗/里程碑筛选,按优先级或 WSJF 重排;卡片带类型、阻塞、范围变更标记 |
94
+ | `/epics` 史诗与目标 | 每个史诗的关键结果(KR)进度、故事完成度、阻塞与缺陷统计 |
95
+ | `/gantt` 甘特图 | 迭代分带,浅色条=计划、实心条=journal 推出的实际执行区间,菱形=里程碑,依赖与阻塞清单 |
96
+ | `/milestones` 里程碑 / MVP | 按 kind 分组,显示达成口径、挂的故事、剩余天数 |
97
+ | `/burndown` 燃尽图 | 实线=真实剩余,虚线=理想线,竖线标出**哪一天插了需求**(范围变更) |
98
+ | `/story/:id` 追溯链 | 验收标准 → 任务 → 每条 red/green/refactor 记录,含测试命令与产出文件 |
99
+
100
+ ## 校验器管什么
101
+
102
+ `validate` 是这套体系的地基,**错误**会让它退出码非 0:
103
+
104
+ - 引用完整性**双向**一致:`epic.stories` ↔ `story.epicId`、`sprint.stories` ↔ `story.sprintId`、`journal.taskId` ↔ task
105
+ - 状态机:story `draft → ready → in-progress → review → done`,task `todo → red → green → refactored → done`(只能前进)
106
+ - **TDD 铁律**:task 到 green 之后,日志必须首条 `fail`、后有 `pass`;done 时末条必须是 `pass`
107
+ - story 到 done:所有 task 必须 done,且不许仍标着 `blocked`
108
+ - 依赖:`dependsOn` 必须存在、不能自依赖、**不能成环**(DFS 检测)
109
+ - 需求属性:`type` / `priority` / `value` 合法;`type: bug` 必须有 `severity` + `environment` + `steps`
110
+ - 验收标准的 `verifyBy` 必须指向同一 story 的 task
111
+ - 迭代 id 格式与序号连续、同时只能有一个活跃迭代
112
+ - 里程碑 `reached` 时挂的故事必须全部完成
113
+
114
+ 给 **WARN** 的(不阻塞):验收没绑验证任务、史诗缺 keyResults、计划区间超出迭代、承诺点数超容量、被阻塞的故事仍排在迭代里等。
115
+
116
+ ## 本地开发
117
+
118
+ ```bash
119
+ pnpm board:dev # Nuxt dev(HMR),读仓库根的 agile/
120
+ AGILE_DIR=/别的项目 pnpm board:dev # 看别的项目的数据
121
+
122
+ pnpm board:build # 构建看板静态产物 → assets/board
123
+ pnpm validate # 只校验数据
124
+ pnpm test # 校验器的回归测试(18 个用例)
125
+ pnpm serve # 起看板(读目标目录的 agile/)
126
+ ```
127
+
128
+ 看板源码在 `apps/board/`(Nuxt 4 + Nuxt UI,纯静态产物,无服务端、无外部字体/图标请求)。`assets/board/` 是构建产物,**不进 git**,发布前由 `prepublishOnly` 自动重建。
129
+
130
+ ## License
131
+
132
+ MIT
@@ -0,0 +1 @@
1
+ <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/DhgUnnc1.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.DEq3ipbJ.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DhgUnnc1.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DuWpPgcw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Brv_Bdja.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DbghXjRj.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BNG0e--z.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/OHMTu69O.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D1zk137d.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BeTHElHy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/C218H_dA.js"><script type="module" src="/_nuxt/DhgUnnc1.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/BWaQPvUU.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DcGinDT7.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/Cxemkb8I.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DW7rSQ02.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CNsYxQaQ.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"cf3421e0-2439-4091-aeea-10c06027154f",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792919574000,false]</script></body></html>
@@ -0,0 +1 @@
1
+ <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/DhgUnnc1.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.DEq3ipbJ.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DhgUnnc1.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DuWpPgcw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Brv_Bdja.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DbghXjRj.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BNG0e--z.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/OHMTu69O.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D1zk137d.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BeTHElHy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/C218H_dA.js"><script type="module" src="/_nuxt/DhgUnnc1.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/BWaQPvUU.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DcGinDT7.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/Cxemkb8I.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DW7rSQ02.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CNsYxQaQ.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"cf3421e0-2439-4091-aeea-10c06027154f",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792919574000,false]</script></body></html>