@haiyangbg/buildbeat 3.3.1 → 4.1.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 (102) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.en.md +20 -124
  3. package/README.md +20 -124
  4. package/SKILL.md +73 -84
  5. package/docs/CAPABILITY-MATRIX.md +30 -39
  6. package/docs/MIGRATION.md +93 -0
  7. package/docs/README.md +8 -37
  8. package/docs/RELEASING.md +4 -3
  9. package/docs/v2/RFC-0001-product-definition.md +3 -0
  10. package/docs/v2/RFC-0002-domain-model.md +3 -0
  11. package/docs/v2/RFC-0003-workflow-policy.md +3 -0
  12. package/docs/v2/SPEC-0001-events-v1.md +3 -0
  13. package/docs/v2/guide/00-how-to-talk.en.md +12 -56
  14. package/docs/v2/guide/00-how-to-talk.md +12 -56
  15. package/docs/v2/guide/01-quickstart.en.md +42 -111
  16. package/docs/v2/guide/01-quickstart.md +42 -111
  17. package/docs/v2/guide/02-workflow-guide.en.md +13 -123
  18. package/docs/v2/guide/02-workflow-guide.md +14 -122
  19. package/docs/v2/guide/03-policy-guide.en.md +6 -50
  20. package/docs/v2/guide/03-policy-guide.md +6 -50
  21. package/docs/v2/guide/04-adapter-guide.en.md +7 -60
  22. package/docs/v2/guide/04-adapter-guide.md +7 -60
  23. package/docs/v2/guide/05-worker-contract.en.md +6 -53
  24. package/docs/v2/guide/05-worker-contract.md +7 -52
  25. package/docs/v2/guide/06-evidence-guide.en.md +8 -44
  26. package/docs/v2/guide/06-evidence-guide.md +9 -43
  27. package/docs/v2/guide/07-approval-guide.en.md +8 -110
  28. package/docs/v2/guide/07-approval-guide.md +8 -121
  29. package/docs/v2/guide/09-security-boundaries.en.md +13 -37
  30. package/docs/v2/guide/09-security-boundaries.md +13 -37
  31. package/docs/v2/guide/10-recovery.en.md +12 -96
  32. package/docs/v2/guide/10-recovery.md +12 -96
  33. package/docs/v2/guide/11-session-handoff.en.md +10 -75
  34. package/docs/v2/guide/11-session-handoff.md +10 -75
  35. package/docs/v2/guide/12-without-runtime.en.md +46 -0
  36. package/docs/v2/guide/12-without-runtime.md +46 -0
  37. package/docs/v2/guide/README.en.md +16 -36
  38. package/docs/v2/guide/README.md +16 -36
  39. package/example/AGENTS.md +15 -69
  40. package/example/README.md +8 -23
  41. package/example/delivery/envelope/prompts/builder.md +3 -1
  42. package/example/delivery/envelope/prompts/fixer.md +3 -1
  43. package/example/delivery/envelope/prompts/reviewer.md +3 -1
  44. package/example/delivery/work/WORK-EXPORT-DATE-FILTER/run-config.yaml +1 -1
  45. package/example//346/214/207/346/214/245/345/217/260.md +8 -40
  46. package/package.json +2 -1
  47. package/src/v2/adapters/notification-payload.js +40 -0
  48. package/src/v2/adapters/shell.js +3 -1
  49. package/src/v2/cli/run-config-check.js +129 -45
  50. package/src/v2/cli/run.js +853 -254
  51. package/src/v2/engine/reducer.js +2 -0
  52. package/src/v2/engine/risk-preset.js +14 -47
  53. package/src/v2/engine/workflow.js +177 -185
  54. package/src/v2/evidence/collector.js +12 -1
  55. package/src/v2/evidence/image.js +346 -0
  56. package/src/v2/policy/policy.js +219 -286
  57. package/src/v2/presets/software-delivery.yaml +1 -16
  58. package/src/v2/runtime/cache.js +22 -1
  59. package/src/v2/runtime/decisions.js +185 -31
  60. package/src/v2/runtime/findings.js +4 -1
  61. package/src/v2/runtime/notify.js +42 -36
  62. package/src/v2/runtime/orchestrator.js +811 -297
  63. package/src/v2/runtime/overview-repos.js +79 -0
  64. package/src/v2/runtime/overview.js +279 -47
  65. package/src/v2/runtime/release.js +233 -0
  66. package/src/v2/runtime/run-record.js +1 -0
  67. package/src/v2/workspace/workspace-manager.js +8 -0
  68. package/templates/v2/AGENTS.md +20 -73
  69. package/templates/v2/BUILDBEAT.md +2 -13
  70. package/templates/v2/envelope/prompts/builder.md +3 -1
  71. package/templates/v2/envelope/prompts/fixer.md +3 -1
  72. package/templates/v2/envelope/prompts/reviewer.md +3 -1
  73. package/templates/v2/run-config.example.yaml +9 -7
  74. package/templates/v2/work.example.md +16 -0
  75. package/templates/v2//346/214/207/346/214/245/345/217/260.md +8 -40
  76. package/docs/v2/skill/01-principles.md +0 -26
  77. package/docs/v2/skill/02-project-layout.md +0 -31
  78. package/docs/v2/skill/03-collaboration-rules.md +0 -45
  79. package/docs/v2/skill/04-rhythm-and-rituals.md +0 -104
  80. package/docs/v2/skill/05-red-lines.md +0 -13
  81. package/docs/v2/skill/06-bootstrap-and-takeover.md +0 -84
  82. package/docs/v2/skill/07-templates-and-lessons.md +0 -24
  83. package/example/.buildbeat/observe.yaml +0 -31
  84. package/src/v2/observe/observe-config.js +0 -194
  85. package/src/v2/observe/observe-reducer.js +0 -117
  86. package/src/v2/observe/observe.js +0 -427
  87. package/src/v2/presets/observe.yaml +0 -45
  88. package/src/v2/presets/policies/ui-render-gate.yaml +0 -13
  89. package/src/v2/presets/release-readback.yaml +0 -36
  90. package/src/v2/presets/risk/controlled.yaml +0 -39
  91. package/src/v2/presets/risk/fast.yaml +0 -19
  92. package/src/v2/presets/risk/release.yaml +0 -21
  93. package/src/v2/presets/risk/standard.yaml +0 -28
  94. package/templates/ARCHITECTURE.md +0 -50
  95. package/templates/contracts/PROTOCOL.md +0 -28
  96. package/templates/pm/adr/ADR-0000-template.md +0 -25
  97. package/templates/pm/adr/README.md +0 -15
  98. package/templates/pm/decisions.md +0 -11
  99. package/templates/standards/CODE.md +0 -23
  100. package/templates/standards/DESIGN.md +0 -36
  101. package/templates/standards/REVIEW.md +0 -20
  102. package/templates/standards/STACK.md +0 -31
@@ -1,41 +1,17 @@
1
- # Security and permission boundaries
1
+ # Security boundaries
2
2
 
3
- [简体中文](09-security-boundaries.md) | **English**
3
+ [简体中文](09-security-boundaries.md)
4
4
 
5
- Authority: [`RFC-0001 §Protected actions`](../RFC-0001-product-definition.md) (Chinese), [`V2-PLAN.md`](../../history/V2-PLAN.md) §9 invariants (Chinese). Design philosophy: **a protected action = a removed capability** — not "please, agent, don't", but making it impossible.
5
+ | Mechanism | Actual boundary |
6
+ |---|---|
7
+ | worktree | Separate candidate directory and branch; not an OS sandbox |
8
+ | allowedPaths | Out-of-scope results cannot become qualified candidates; not filesystem access control |
9
+ | read-only review | Compare Git state and reject changed results; not host write prevention |
10
+ | push restriction | Override configured remote push URLs in the worktree; not a network sandbox |
11
+ | env allowlist | Limit inherited variables; HOME files, keychains and SSH files remain outside it |
12
+ | approval and evidence | Bind current candidate, work digest, evidence and frozen safeguards |
13
+ | concurrency locks | Local repository coordination with per-Work exclusion; no cross-machine scheduler |
6
14
 
7
- ## Local boundaries on the Runner side (LOCAL_ENFORCED, all tested)
15
+ Host sandboxing, production credential isolation and server branch protection need their respective platforms. The runner has no merge/push/deploy/publish call path, but arbitrary external workers still have their actual host permissions.
8
16
 
9
- Each row has two columns: **what the kernel actually does**, and **what cannot be concluded from it**. The former has regression tests; the latter depends on the host's sandbox / container / server, and the Runner does not pretend otherwise.
10
-
11
- | Boundary | What the kernel actually does (detection or removal) | What cannot be concluded from it |
12
- |---|---|---|
13
- | Push blocked | Worktree-level `remote.pushurl=protected://push-blocked-by-buildbeat` — inside the workspace, a worker's `git push` to a configured remote has nowhere to go (tested against a real remote) | That a worker cannot `git remote add` another remote, or make any network request |
14
- | Write scope | An out-of-scope write under `allowedPaths` → no candidate pinned, `workspace.scope` BLOCK recorded, the Run stops — an out-of-scope change **cannot** become a qualifying candidate | That the worker process cannot touch host directories outside the worktree |
15
- | Read-only reviewer | A before/after snapshot comparison per step; any write to the worktree is recorded as a failure (invariant 9) — this is **detecting and blocking the result after the fact**, not an operating-system write ban | That the write is stopped the moment it happens |
16
- | Credential isolation | The worker env allowlist is by default only `PATH HOME LANG LC_ALL TMPDIR TERM USER SHELL`; cloud-credential / token **environment variables** in the host shell do not reach the subprocess; opening it explicitly with `inheritEnv: true` is labelled ADVISORY by doctor; `env:` injects only the variables you name (really passed through on the CLI loading path since 2.0.1; in 2.0.0 and earlier doctor and start disagreed, see the [Adapter guide](04-adapter-guide.en.md)) | That a worker cannot read credential files under `$HOME`, the keychain, ssh keys or other host resources (`HOME` is on the allowlist) |
17
- | One active Run | By default a repository-wide lock, so a repository drives one Run at a time; Works whose run configs set `parallel: true` may run in parallel with each other, and Runs of the same Work stay mutually exclusive (since 3.2.0) | That concurrency across repositories / machines is coordinated |
18
- | Control files | Workflow / policy / run configs live in the main checkout, outside the worker worktree's write scope | That a worker cannot read them by other means |
19
- | No external actions in the kernel | Merge, push, deploy and publish have **no call path** in the Runner (invariant 20, printed by doctor); at most the Runner puts "the candidate is fit to merge" in the inbox | That any external worker command you configure cannot do these things in every host environment |
20
-
21
- In one sentence: **the kernel guarantees that an out-of-bounds result cannot enter the ledger, become a candidate or get stamped**; "the worker cannot do it in the first place" depends on the sandbox the host gives it (a tool allowlist, egress limits, no production credentials).
22
-
23
- ## Preconditions for running unattended (the stance enforced since the MVP)
24
-
25
- Prompt injection is a first-class attack surface: an unattended worker consumes any file in the repository. An unattended run must satisfy all three layers at once; missing any layer downgrades it to attended (a human in the loop):
26
-
27
- | Layer | Who guarantees it | What |
28
- |---|---|---|
29
- | Kernel | The Runner (the section above) | Push blocked, write scope, read-only reviewer, env allowlist, no call path for external actions |
30
- | Host | Your worker sandbox / container / the tool's own permission mode (such as `codex exec -s read-only`) | A tool allowlist, egress limits, **no production credentials** — the kernel does not and cannot check this layer; doctor reports only the env posture |
31
- | Server | Code hosting / CI / deployment platform | Branch protection, required CI, deployment approval (next section) |
32
-
33
- observe's diagnose commands follow the same discipline: read-only, same env allowlist.
34
-
35
- ## SERVER_ENFORCED is an honest declaration
36
-
37
- Branch protection, required CI and deployment approval are enforced by the server; marking a policy `SERVER_ENFORCED` says "this gate lives on the server", and the Runner records it without pretending it can guarantee it locally. Never mark as LOCAL what cannot be stopped locally.
38
-
39
- ## Credential red line (operations)
40
-
41
- Credentials for publishing / deploying are read only at run time (for example from the macOS Keychain), never written to files, logs or Git; `doctor` checks the adapter's env posture. A configuration that breaks the red line should not pass review.
17
+ BuildBeat does not collect or upload project usage data. Configured AI tools and notification services have their own data handling.
@@ -1,41 +1,17 @@
1
- # 安全与权限边界
1
+ # 安全边界
2
2
 
3
- **简体中文** | [English](09-security-boundaries.en.md)
3
+ [English](09-security-boundaries.en.md)
4
4
 
5
- 权威:[`RFC-0001 §保护动作`](../RFC-0001-product-definition.md)、[`V2-PLAN.md`](../../history/V2-PLAN.md) §9 不变量。设计哲学:**保护动作 = 能力移除**——不是"请 Agent 别做",而是让它做不到。
5
+ | 机制 | 实际边界 |
6
+ |---|---|
7
+ | worktree | 候选在独立目录与分支;并非操作系统沙箱 |
8
+ | allowedPaths | 越界结果不成为合格候选;不是事前文件系统禁写 |
9
+ | reviewer 只读 | 前后 Git 状态检查并阻断写入结果;不是宿主禁写权限 |
10
+ | push 限制 | 工作树配置的远端 pushurl 被移除;不保证任意命令无法新增远端或出网 |
11
+ | env 白名单 | 限制继承的环境变量;不隔离 HOME 文件、密钥串或 SSH 文件 |
12
+ | 批准与证据 | 当前候选、工作摘要、证据和冻结校验匹配才批准 |
13
+ | 并行与锁 | 同一仓库本地协调,同 Work 互斥;没有跨机器调度器 |
6
14
 
7
- ## Runner 侧的本地边界(LOCAL_ENFORCED,均有测试)
15
+ 宿主沙箱、生产凭据隔离和服务端分支保护需要平台分别提供。Runner 没有 merge/push/deploy/publish 调用路径,但任意外部 worker 仍受其宿主实际权限约束。
8
16
 
9
- 下表每行分两栏:**内核实际做到的**,与**不能由此推出的**。前者有回归测试;后者要靠宿主沙箱 / 容器 / 服务端,Runner 不冒充。
10
-
11
- | 边界 | 内核实际做到的(检测或移除) | 不能由此推出 |
12
- |---|---|---|
13
- | push 封禁 | worktree 级 `remote.pushurl=protected://push-blocked-by-buildbeat`——Worker 在工作区内对配置的 remote `git push` 无处可推(真实 remote 上实测) | Worker 不能 `git remote add` 另一个远端、不能发起任何网络请求 |
14
- | 写范围 | `allowedPaths` 越界写入 → 不固定 candidate、`workspace.scope` BLOCK 落账、Run 停——越界改动**不可能**成为合格候选 | Worker 进程无法触碰 worktree 之外的宿主目录 |
15
- | Reviewer 只读 | 步级前后快照比对,任何工作树写入按失败落账(不变量 9)——这是**事后检测并阻断结果**,不是操作系统级禁写 | 写入在发生那一刻就被拦下 |
16
- | 凭据隔离 | Worker env 默认白名单仅 `PATH HOME LANG LC_ALL TMPDIR TERM USER SHELL`;宿主 shell 里的云凭据 / token **环境变量**不进子进程;`inheritEnv: true` 显式打开会被 doctor 标为 ADVISORY;`env:` 只注入你点名的变量(CLI 加载路径 2.0.1 起真正透传,2.0.0 及更早 doctor 与 start 姿态不一致,见 [Adapter 指南](04-adapter-guide.md)) | Worker 读不到 `$HOME` 下的凭据文件、keychain、ssh key 等宿主资源(`HOME` 在白名单里) |
17
- | 单活动 Run | 默认仓库级锁,一仓同时只驱动一个 Run;run 配置 `parallel: true` 的 Work 之间可并行,同一 Work 的 Run 仍互斥(自 3.2.0) | 多仓 / 多机并发有协调 |
18
- | 控制文件 | workflow / policy / run 配置在主检出,不在 Worker 的 worktree 写范围内 | Worker 无法通过其他途径读到它们 |
19
- | 内核无外部动作 | merge、push、部署、发布在 Runner **没有调用路径**(不变量 20,doctor 打印);Runner 至多把"候选具备合并条件"放进 inbox | 你配置的任意外部 Worker 命令在全部宿主环境下都做不了这些动作 |
20
-
21
- 一句话:**内核保证的是"越界的结果进不了台账、成不了候选、盖不了章"**;"Worker 一开始就做不到"要靠宿主给它的沙箱(工具白名单、出网限制、无生产凭据)。
22
-
23
- ## 无人值守的前置条件(MVP 起强制的立场)
24
-
25
- prompt injection 是一等攻击面:无人值守 Worker 会消费仓库内任意文件。unattended run 必须同时满足三层,缺一层就降级 attended(人在环):
26
-
27
- | 层 | 谁保证 | 内容 |
28
- |---|---|---|
29
- | 内核 | Runner(本表上节) | push 封禁、写范围、只读 reviewer、env 白名单、无外部动作调用路径 |
30
- | 宿主 | 你的 worker 沙箱 / 容器 / 工具本身的权限模式(如 `codex exec -s read-only`) | 工具白名单、出网限制、**无生产凭据**——内核不检查也检查不了这层,doctor 只报告 env 姿态 |
31
- | 服务端 | 代码托管 / CI / 部署平台 | 分支保护、必需 CI、部署审批(下节) |
32
-
33
- observe 的 diagnose 命令同理只读、同 env 白名单纪律。
34
-
35
- ## SERVER_ENFORCED 是诚实声明
36
-
37
- 分支保护、CI 必须、部署审批属于服务端强制;Policy 里标 `SERVER_ENFORCED` 表示"这道门在服务端",Runner 落账但不冒充能本地保证。本地挡不住的永远不要标 LOCAL。
38
-
39
- ## 凭据红线(运维侧)
40
-
41
- 发布/部署用的凭据只在运行时读取(如 macOS Keychain),不落文件、不落日志、不进 Git;`doctor` 检查 adapter 的 env 姿态。违反红线的配置不应通过评审。
17
+ 不采集或上传项目使用数据;配置的 AI 工具与通知服务有各自的数据处理方式。
@@ -1,99 +1,15 @@
1
- # Recovery handbook
1
+ # Recovery and diagnostics
2
2
 
3
- [简体中文](10-recovery.md) | **English**
3
+ [简体中文](10-recovery.md)
4
4
 
5
- Design premise (invariant 23 in [`V2-PLAN.md`](../../history/V2-PLAN.md), Chinese): **the whole `.buildbeat/runtime/` directory can be deleted at any time**. Accepted artifacts, decisions, Intent drafts with their triage, and the compacted records of finished Runs all live in the Git plane. "Delete and rebuild" is the default troubleshooting move, not the last resort.
5
+ - run resumes the unique nonterminal run in its family; choose --run when ambiguous. Archived work needs explicit --new to start another attempt.
6
+ - An interrupted step reruns itself from the ledger. Handle a dirty worktree first. After committing a manual fix, --adopt checks the actual HEAD and continues at verify.
7
+ - Reclaim a lock only when its owner is on this host and provably dead. Keep live, foreign-host and unidentified locks. stop is not a process-kill command.
8
+ - Timeouts, crashes, malformed envelopes and exit 75 are infra: no fixer and no failure-budget charge. Decide and continue once the environment recovers.
9
+ - A corrupt ledger exposes only its valid prefix and refuses appends. history --verify replays and validates without silently repairing it. Preserve the scene and candidate.
10
+ - Changed workflow digests or frozen safeguards prevent resume. Unsupported old custom/release flows must finish on the old runtime.
11
+ - Terminal records survive runtime cleanup; active process/worktree state does not migrate through Git. Do not routinely delete runtime files.
12
+ - gc plans first and only collects compacted terminal runs. Dirty trees and unique candidates are retained by default; stale lock owners must be proven dead.
13
+ - STALLED defaults to 15 minutes without output. Status shows elapsed/typical duration and recent output; it does not kill processes.
6
14
 
7
- ## Symptom → action
8
-
9
- ### "run config … has N problem(s)"
10
-
11
- The run config has mistakes; no Run started and nothing changed. Fix the list item by item (each names the key, what is wrong and the closest valid spelling), then rerun the same command; `buildbeat doctor --config …` checks it on its own first.
12
-
13
- ### The ledger reports corrupted
14
-
15
- `status`/`inbox` shows `LEDGER CORRUPTED after seq=N (<reason>)`: the ledger truncates its view at the last valid event and **refuses to append**; recovery is a human decision, nothing is repaired silently.
16
-
17
- 1. `buildbeat events --repo . --run RUN-X` shows the valid prefix; `replay` verifies the reduction;
18
- 2. If the broken Run is in flight: usually abandon it (the candidate in the worktree is still readable on its branch) and start a new Run;
19
- 3. If someone edited the ledger file by hand: rebuild the judgement from Git-plane facts; do not patch event lines by hand.
20
-
21
- ### The Run process was killed / the machine rebooted
22
-
23
- ```bash
24
- buildbeat resume --config <run-config.yaml>
25
- ```
26
-
27
- After `start --attempt new` numbers a Run, `resume --config <run-config.yaml>` resumes the family’s only non-terminal Run and prints its ID. Use `--run <RUN-ID>` to select the configured Run itself or `<family>-NN` explicitly (at least two digits). An existing ledger for the exact configured ID takes precedence. Multiple non-terminal Runs are listed with a request to select one using `--run`; if none remain, the error reports the latest ID and terminal status, or states that no ledgers were found.
28
-
29
- The in-flight step is closed as `crashed` (the fact is recorded), then **the step itself is rerun** (changed in beta.3): a dead process says nothing about the candidate; the lost attempt still counts against the step's budget, and an exhausted budget stops for a human. The earlier semantics treated a crash as a step failure and followed the failure edge; real incident (deploy-18): the host tool's timeout killed the verify worker, the crash was routed to fix, and the fixer burned a round facing zero verifier evidence. A dirty worktree still stops for a human first. Resuming with approvals re-checks candidate/plan freshness and turns `APPROVAL_STALE` over to a human if anything changed. If it cannot be recovered, delete the runtime and rerun: the candidate branch and the Git-plane records are not lost.
30
-
31
- **Launch discipline** (the other half of the same incident): a Run longer than minutes must be launched in a way that escapes the host tool's timeout (`nohup`/`setsid`); `start` prints this reminder in an interactive shell.
32
-
33
- ### A stuck lock ("another run is active")
34
-
35
- Every lock records its owner (pid, host name, time acquired, command). When a driver is killed, ended by a host-tool timeout or lost to a reboot, its locks stay behind; the next `resume` / `stop` / `start` that needs the lock reclaims it automatically when the owner is **on this host and its process no longer exists**, printing `reclaimed stale lock <id> (owner pid … is gone)`. No file needs deleting by hand. After a killed driver, simply run:
36
-
37
- ```bash
38
- buildbeat resume --config <run-config.yaml>
39
- ```
40
-
41
- The kernel takes the crash-recovery path above (`RUN_INTERRUPTED`, then the interrupted step reruns); if you would rather not continue, `buildbeat stop --repo . --run RUN-X --reason "…"`.
42
-
43
- Only three cases still answer `another run is active` / `already locked`, and the error names the owner:
44
-
45
- - **The owner is alive**: another Run really is driving; wait for it, or end that process once you are sure it is stuck;
46
- - **The owner is on another host** (a repository on a shared disk): deal with it on that machine; this host never reclaims it;
47
- - **No owner record**: a lock left by an older buildbeat, or a crash in the instant of taking it; once no buildbeat process is running, delete the lock directory the error names.
48
-
49
- ### Ledger "changed on disk since it was read"
50
-
51
- `ledger for RUN-X changed on disk since it was read (another writer); re-read it and retry`: another session or process wrote the same Run's ledger just before you (two approvals at once, a `stop` racing a `resume`). The kernel refused this write; **the ledger was not changed and is not corrupted**. Run the same command again: it decides afresh on the current state (and may simply tell you it is already approved or terminal). Approve, reject, `--adopt`, `stop`, `resume` and supersede all read the ledger only after taking the Run lock, so ordinary use never meets this error; seeing it means there really was a concurrent operation.
52
-
53
- ### Abnormal worker behaviour
54
-
55
- - **Worker infrastructure failure (iteration 09)**: a timeout, a crash, output that is not an envelope (`invalid-output`), or the worker ending itself with exit code **75** (`EX_TEMPFAIL`, "environment unavailable"): the kernel classifies it as `infra`: no failure fingerprint is recorded, no fixer is dispatched, **the step's budget is not consumed**, the Run stops at `WAITING_HUMAN` (kind `infra`, transition `resume-<step>`), notifications go out as usual. Once the backend is back, `approve --transition resume-<step>` reruns the step; `reject` ends the Run. Real incidents: a worker backend returning 404 and non-JSON output killed five Runs in two days while the driving session hand-wrote a probe every two minutes; a missing rg on PATH, a port collision and a host load of 280 each dispatched a fixer.
56
- - **A failure with no transition edge** (such as `failed` on build / review / fix in the preset) no longer ends in FAILED; it stops at `resume-<step>` as well, and a human decides whether to rerun or end.
57
- - Out-of-scope writes → the Run BLOCKs and no candidate is pinned: check `allowedPaths` and the scope declared in the worker prompt;
58
- - Timeouts → first check whether it is the environment (`infra` already stopped for you), then adjust `timeoutMs`; an exhausted budget is a brake, not a fault: approve `resume-<step>` to grant one more attempt, or narrow the scope.
59
-
60
- ### The observe plane
61
-
62
- - A probe stays `unverified`: fix the probe's reachability first; unverified means "could not collect", not "no problem";
63
- - False alarms flooding: `observe triage --action dismiss`; the same fingerprint stays out of the queue until its severity rises;
64
- - Observe cycle counts reset to zero after the runtime was deleted: normal; triage memory lives in the Git-plane drafts, and suppression keeps working (tested).
65
-
66
- ### Everything is a mess
67
-
68
- ```bash
69
- rm -rf .buildbeat/runtime/
70
- ```
71
-
72
- Then start again from the Git plane. Any phenomenon where a long-term metric or a terminal-state explanation depends on the runtime is a bug; please report it.
73
-
74
- ## Diagnostic entry point
75
-
76
- `buildbeat doctor --config <run-config>`: the config parses, the workflow has no exit loop, adapter env posture, digests can be computed, supersede and stall thresholds, whether the notification channel and its environment variable are in place. `events`/`replay`/`metrics` are all read-only and can run at any time.
77
-
78
- ## "Is it stuck?"
79
-
80
- > Since 2.0.0-beta.4 (iteration 08).
81
- Look at `buildbeat status --repo . --run <RUN>` first: the step in flight shows elapsed time, the repository's historical median, the worker command, how long ago the last output was and its last three lines. No output beyond the threshold (default 15 minutes, `--stall-after <minutes>` or `stallAfterMs` in the run config) marks `STALLED`: **marked, never killed**. How to judge:
82
-
83
- - Output keeps coming → wait (compare against `typical` to see whether it is far beyond the median);
84
- - STALLED and the worker is an agent CLI → most likely a long reasoning stretch or waiting for an interaction that never comes; `stop --reason`, then rerun by the crash recovery path (the interrupted step reruns itself);
85
- - STALLED and the worker is a script → read the last three lines; usually it waits on an external resource (port, lock, network).
86
-
87
- To avoid watching the screen, subscribe to `STALLED` notifications ([Approval guide](07-approval-guide.en.md)). `watch --repo . --run <RUN> --once true` probes once by hand.
88
-
89
- ## Cleanup: gc
90
-
91
- > Since 2.0.0-beta.4 (iteration 08).
92
- Terminal Runs leave worktrees, `run/*` branches and the occasional lock. `buildbeat gc --repo .` prints the plan by default, `--apply true` executes it:
93
-
94
- - It touches only Runs that are **terminal and already compacted into a run-record** (the Git plane must have the record before the runtime plane is touched);
95
- - Worktrees may be deleted (the commits are on the branch); a dirty worktree is left alone without `--force true`;
96
- - A branch is deleted only when the candidate **is reachable from another ref** (merged / tagged / on the remote) or the Run produced no candidate; otherwise it reports "reachable only from this branch, kept": that branch is the last thread to the evidence;
97
- - Leftover `locks/<RUN>.lock` of terminal Runs are cleaned; the `active-run` lock is reclaimed too when its owner process is gone (the plan names the owner), and kept with the reason when the owner is alive, on another host, or unrecorded.
98
-
99
- gc never writes to the ledger (after the terminal state only `RUN_COMPACTED` is allowed), so it can run at any time and repeatedly.
15
+ [Migration and rollback](../../MIGRATION.md).
@@ -1,99 +1,15 @@
1
- # 故障恢复手册
1
+ # 恢复与诊断
2
2
 
3
- **简体中文** | [English](10-recovery.en.md)
3
+ [English](10-recovery.en.md)
4
4
 
5
- 设计前提([`V2-PLAN.md`](../../history/V2-PLAN.md) 不变量 23):**`.buildbeat/runtime/` 整个目录随时可删**——已接受工件、Decision、Intent 草稿与分诊、已终结 Run 的压实记录全部活在 Git 面。"删了重建"是默认排障手段,不是最后手段。
5
+ - run 自动续接已有家族的唯一未终态 Run;多个候选时必须 --run 指定。历史工作需明确 --new 才会重新启动。
6
+ - 中断步按台账重跑自身;脏工作树先处理。手修并提交后用 --adopt 指定实际 HEAD,从 verify 继续。
7
+ - 只有同机且持有者进程已不存在的锁自动回收。活动、异机、缺持有者信息的锁保留;stop 不是杀进程命令。
8
+ - 超时、崩溃、无效信封、exit 75 属于 infra,不派 fixer、不扣失败预算。环境恢复后按待决策对象处理并续跑。
9
+ - 台账损坏只读取合法前缀,拒绝追加;history --verify 校验回放,不会静默修复。保留现场与候选后决定恢复方式。
10
+ - 运行配置或冻结校验变更时拒绝恢复。新主版本不继续不支持的旧自定义/上线流程;见迁移指南。
11
+ - runtime 被删后,终态记录可读,活动运行的现场不能凭 Git 自动恢复;不要把删 runtime 当作日常清理。
12
+ - gc 先给计划,只清终态且已归档的运行。脏树默认保留,唯一候选引用保留,失效锁需证实持有者已退出。
13
+ - STALLED 默认指 15 分钟无输出,status 给出实际耗时、历史中位数、最近输出;它只提示,不自动杀进程。
6
14
 
7
- ## 症状 → 处置
8
-
9
- ### 「run config … has N problem(s)」
10
-
11
- run 配置写错了,Run 没有起跑、什么都没改。按清单逐条改(每条写明是哪个键、错在哪、最接近的正确拼写),改完再跑同一条命令;`buildbeat doctor --config …` 可以先单独核对。
12
-
13
- ### 台账报 corrupted
14
-
15
- `status`/`inbox` 出现 `LEDGER CORRUPTED after seq=N (<原因>)`:台账在最后一条合法事件处截断视图并**拒绝追加**——恢复是人的决定,不静默修复。
16
-
17
- 1. `buildbeat events --repo . --run RUN-X` 看合法前缀;`replay` 校验归约;
18
- 2. 若坏的是在途 Run:通常直接废弃该 Run(worktree 里的候选仍在分支上可读),新起一个 Run;
19
- 3. 若人为改过台账文件:从 Git 面事实重建判断,不要手补事件行。
20
-
21
- ### Run 进程被杀 / 机器重启
22
-
23
- ```bash
24
- buildbeat resume --config <run-config.yaml>
25
- ```
26
-
27
- 使用 `start --attempt new` 自动编号时,`resume --config <run-config.yaml>` 会续跑该家族唯一未终态的 Run,并打印选中的 ID;也可用 `--run <RUN-ID>` 显式指定配置中的 Run 本身或 `<家族>-NN`(数字至少两位)。配置本身已有台账时优先使用该精确 ID。多个未终态 Run 会列出候选并要求用 `--run` 选择;没有未终态 Run 会报告最新一次的 ID 和终态,没有台账则明确说明。
28
-
29
- 在途步会以 `crashed` 关闭(事实落账),然后**重跑该步本身**(beta.3 改):进程死掉不说明候选有问题,丢失的那次尝试照常计入该步预算,预算耗尽即停人工。此前的语义是把 crash 当步骤失败走 failure 边——真实事故(deploy-18):宿主工具超时杀掉 verify worker,crash 被路由去 fix,fixer 面对零 verifier 证据白烧一轮。工作树脏了仍然先停人工。带批准恢复时会做 candidate/plan 新鲜度检查,变了即 `APPROVAL_STALE` 转人工。恢复不了就删 runtime 重跑——候选分支与 Git 面记录不丢。
30
-
31
- **启动纪律**(同一事故的另一半):长于分钟级的 Run 必须以脱离宿主工具超时的方式启动(`nohup`/`setsid`),交互式 shell 里 `start` 会打印这条提醒。
32
-
33
- ### 锁卡住("another run is active")
34
-
35
- 每把锁记录持有者(进程号、主机名、获取时间、命令)。驱动进程被杀、被宿主超时结束或机器重启后,锁会残留;下一次 `resume` / `stop` / `start` 拿锁时,若持有者**在本机且进程已不存在**,自动回收并打印 `reclaimed stale lock <id> (owner pid … is gone)`,无需手删任何文件。所以驱动被杀后直接:
36
-
37
- ```bash
38
- buildbeat resume --config <run-config.yaml>
39
- ```
40
-
41
- 内核走上文的崩溃恢复(`RUN_INTERRUPTED` → 重跑中断步);不想续跑就 `buildbeat stop --repo . --run RUN-X --reason "…"`。
42
-
43
- 只有三种情况仍会报 `another run is active` / `already locked`,报错里写明持有者:
44
-
45
- - **持有者还活着**:另一个 Run 真的在跑,等它结束;确认它卡死再结束该进程;
46
- - **持有者在别的主机**(共享盘上的仓库):到那台机器处理,本机不会替它回收;
47
- - **没有持有者信息**:旧版本 buildbeat 留下的锁,或拿锁瞬间崩溃;确认没有 buildbeat 进程在跑后,删除报错里给出的那个锁目录。
48
-
49
- ### 台账「changed on disk since it was read」
50
-
51
- `ledger for RUN-X changed on disk since it was read (another writer); re-read it and retry`:另一个会话或进程刚好在你之前写了同一个 Run 的台账(例如两边同时批准、一边 `stop` 一边 `resume`)。内核拒绝了这次写入,**台账没有被改动、也没有损坏**;重新执行同一条命令即可,它会基于最新状态重新判断(可能直接告诉你「已经批过了 / 已终态」)。批准、拒绝、`--adopt`、`stop`、`resume` 与自动取代都在拿到 Run 锁之后才读台账,正常使用不会遇到这条报错;看到它说明确实有并发操作。
52
-
53
- ### Worker 行为异常
54
-
55
- - **worker 基础设施故障(迭代 09)**:超时、崩溃、输出不是信封(`invalid-output`)、或 worker 自己以退出码 **75**(`EX_TEMPFAIL`,"环境不可用")结束——内核判为 `infra`:不记失败指纹、不派 fixer、**不扣该步预算**,停 `WAITING_HUMAN`(kind `infra`,transition `resume-<step>`),通知照常出站。后端恢复后 `approve --transition resume-<step>` 重跑该步;`reject` 结束 Run。真实事故:worker 服务端 404 与非 JSON 输出两天杀掉 5 个 Run,驾驶会话手写探针每两分钟试一次;PATH 缺 rg、端口撞车、宿主负载 280 各派了一次 fixer。
56
- - **没有转移边的失败**(如预设里 build / review / fix 的 `failed`)不再终态 FAILED,同样停 `resume-<step>` 由人决定重跑或结束。
57
- - 越界写入 → Run BLOCK 且不固定 candidate:检查 `allowedPaths` 与 Worker prompt 的范围声明;
58
- - 超时 → 先看是不是环境(`infra` 已停人),再调 `timeoutMs`;超预算 → 这是刹车不是故障,批准 `resume-<step>` 即多给一次,或收 scope。
59
-
60
- ### observe 面
61
-
62
- - 探针一直 `unverified`:先修探针可达性——unverified 是"采不到",不是"没问题";
63
- - 误报刷屏:`observe triage --action dismiss`,同指纹在严重度升级前不再入队;
64
- - 删了 runtime 后 observe 周期数归零:正常——分诊记忆在 Git 面草稿里,抑制照常生效(有测试)。
65
-
66
- ### 一切都乱了
67
-
68
- ```bash
69
- rm -rf .buildbeat/runtime/
70
- ```
71
-
72
- 然后从 Git 面重新出发。任何"长期度量/终态解释依赖 runtime"的现象都是 bug,请报告。
73
-
74
- ## 诊断入口
75
-
76
- `buildbeat doctor --config <run-config>`:配置可解析、workflow 无出口环、adapter env 姿态、digest 可算、supersede 与 stall 阈值、通知通道与环境变量是否就位。`events`/`replay`/`metrics` 全部只读,可随时跑。
77
-
78
- ## "是不是卡住了"
79
-
80
- > 自 2.0.0-beta.4(迭代 08)起。
81
- 先看 `buildbeat status --repo . --run <RUN>`:在飞步骤有已用时间、同仓历史中位数、worker 命令、最后一次输出距今多久与末三行输出。无输出超过阈值(默认 15 分钟,`--stall-after <分钟>` 或 run 配置 `stallAfterMs`)标 `STALLED`——**只标不杀**。判断口径:
82
-
83
- - 有输出在持续 → 等(对照 `typical` 看是否已远超中位数);
84
- - STALLED 且 worker 是 Agent CLI → 多半在长推理或等一个永远不来的交互,`stop --reason` 后按崩溃恢复重跑(中断的步重跑自身);
85
- - STALLED 且 worker 是脚本 → 看末三行,通常是等外部资源(端口、锁、网络)。
86
-
87
- 想不盯屏就订阅 `STALLED` 通知([Approval 指南](07-approval-guide.md))。`watch --repo . --run <RUN> --once true` 可手工探测一次。
88
-
89
- ## 打扫卫生:gc
90
-
91
- > 自 2.0.0-beta.4(迭代 08)起。
92
- 终态 Run 会留下工作树、`run/*` 分支和偶尔的锁。`buildbeat gc --repo .` 默认只出计划,`--apply true` 执行:
93
-
94
- - 只动**终态且已压成 run-record** 的 Run(Git 面有账才动运行时面);
95
- - 工作树可删(提交都在分支上);脏工作树不带 `--force true` 不动;
96
- - 分支只在候选**已可从其他 ref 到达**(已合并 / 打 tag / 在远端)或 Run 未产出候选时删;否则明示"仅此分支可达,保留"——它是证据的最后一根线;
97
- - 终态 Run 的残留 `locks/<RUN>.lock` 一并清;`active-run` 锁在持有者进程已不存在时一并回收(计划里写明持有者),持有者还活着 / 在别的主机 / 没有持有者信息时保留并说明原因。
98
-
99
- gc 永不写台账(终态后只允许 `RUN_COMPACTED`),所以随时可跑、可重复。
15
+ [迁移与回退](../../MIGRATION.md)。
@@ -1,84 +1,19 @@
1
- # Session handoffs: close the chat, keep the work
1
+ # Session handoff
2
2
 
3
- [简体中文](11-session-handoff.md) | **English**
3
+ [简体中文](11-session-handoff.md)
4
4
 
5
- BuildBeat uses project files, Git, and run ledgers to continue work. A fresh session reads those facts to decide whether to proceed, recover an interrupted Run, handle a pending decision, or prepare the next Run for the same Work. The person taking over can be you or another teammate. The handoff does not need the old chat transcript, and it does not automatically save discussion that exists only in that chat.
5
+ Before closing a session, save the goal, decisions, unverified scope and next step. Check Git, candidate and run state. Preserve active ledgers and worktrees.
6
6
 
7
- ## Before closing the old session
7
+ A new session reads AGENTS.md, work.md (or legacy intent/plan), decisions and status. Verify available facts and reuse still-valid authorization. A new conversation is not permission to start a duplicate run.
8
8
 
9
- Tell the current session:
9
+ For a main repository managing several code repositories, start with `buildbeat status --repo . --all-repos`. This reads the main checkout, targets named by `repo:` in its `delivery/work/` run configurations, and immediate child Git checkouts containing `delivery/work/`. Discovery deduplicates real paths and never recurses. Missing or invalid targets and unreadable configurations produce warnings without hiding other repositories.
10
10
 
11
- > I am switching sessions. Save context needed to continue that is still only in this chat. Check the current Work, candidate, unverified items, pending decisions, and run state.
11
+ Pending decisions come first, followed by open work grouped by repository. CLOSED, CANCELLED and merged work whose configuration has no `release:` are counted only. Merged work with `release:` remains visible until closed. `--json` returns `{repos: [{repo, works, settled}], pending, warnings}` including settled work. `--work <ID>` filters the merged results; `--run` cannot be combined with `--all-repos`.
12
12
 
13
- The session should check that:
13
+ When a configured target has the matching work directory or a runtime ledger, its state, findings and decisions are authoritative and the work appears only under that repository. Suggested commands retain the main repository's configuration and use paths relative to the caller; fill in person/reason placeholders before executing. Work without target records remains under the main repository with its runtime target shown. Single-repository `status` also reads this one level of target state, preventing duplicate-start suggestions.
14
14
 
15
- - Goals, scope, acceptance criteria, and decisions have a clear home in project files. Recording facts must not rewrite approvals or turn an unaccepted idea into an accepted plan.
16
- - Candidate commits, uncommitted changes, verification evidence, and the next step are identifiable. Save necessary environment facts in the Work's `env-facts.md`; reference the source of secrets without copying their values into project records.
17
- - `overview`, `inbox`, and `status` reflect the actual state. If a Run is active, explain whether its process is detached from the driving session. State uncertainty when this cannot be confirmed.
18
- - Project records and candidate branches are committed and synchronized under existing authorization when another machine or collaborator needs them. Saved to disk does not mean committed or pushed.
15
+ Changing tools requires command, authentication and output-contract configuration. Records remain reusable; execution capability needs validation. Handoffs between people require candidate, records, access and a named next owner/action.
19
16
 
20
- When these facts are already saved, each handoff does not need another long report. Removing a chat should retain the project directory, run ledger, and worktree. Some tools also remove temporary workspaces when deleting a task; check what the operation actually removes.
17
+ Git transfers long-lived facts between machines. Active processes, runtime files, worktrees and host resources do not migrate with clone. Inspect the original environment before choosing how to continue.
21
18
 
22
- ## Taking over in a new session
23
-
24
- Open a fresh session in the **same project directory**. Load the BuildBeat Skill and the project's `AGENTS.md` using the target tool's supported mechanism, then say:
25
-
26
- > Continue this project. Read its BuildBeat entry point and active work first. Check Git, progress, verification results, and pending decisions, then proceed within existing authorization.
27
-
28
- The session reads current facts first:
29
-
30
- ```bash
31
- buildbeat overview --repo .
32
- buildbeat inbox --repo .
33
- ```
34
-
35
- It then reads the goal, plan, decisions, and configuration under the relevant `delivery/work/<ID>/`. For active Run details, use `status --repo . --run <RUN-ID>`. Read IDs from actual output rather than guessing from a conversation.
36
-
37
- | Observed state | Next action |
38
- |---|---|
39
- | A Run is executing normally | Observe it; avoid starting a duplicate or modifying its worktree |
40
- | A Run awaits a human decision | Show the current subject and evidence; a new session does not create a missing approval or renew a stale one |
41
- | The Runner was interrupted; its ledger and worktree remain | Inspect the state and follow recovery guidance, then `resume --config <configuration-path>`; the interrupted step may run again |
42
- | Dirty worktree, changed configuration, stale approval, or missing state | Explain the specific difference and follow the runtime's handling; do not claim lossless recovery |
43
- | A Run is terminal, but its Work needs another execution | Prepare the next Run from existing artifacts and the candidate; terminal Runs do not reopen |
44
- | The work is already merged or released | Read back Git or release facts; do not repeat work because an earlier Run was canceled |
45
-
46
- Recovery approval and the final merge decision are distinct actions. See [approvals](07-approval-guide.md) and [run recovery](10-recovery.md) (Chinese).
47
-
48
- ## Another teammate takes over
49
-
50
- The person handing over saves shared goals, plans, decisions, acceptance records, and the next step in project files, synchronizes them with the shared repository under existing authorization, and makes candidate commits reachable. Record who will carry the Work forward, whether its original Run is still active, and where it is executing. Actual readback remains authoritative for run state.
51
-
52
- Once granted project access, the next teammate syncs the relevant files and candidate branches, loads the project entry point, and uses their own AI tool to inspect scope, evidence, pending decisions, and environment. Existing valid decisions remain in effect. Taking over does not automatically grant someone else's merge, release, or credential permissions.
53
-
54
- If the original Run is not terminal, check its execution environment first. An empty `overview` or `inbox` on a new machine does not show that the old machine has no active Run. Local locks do not coordinate different machines or Git clones; do not start duplicate work on that basis. Before executing in a new environment, settle how the original Run will be handled, then prepare subsequent execution from synchronized artifacts and candidates.
55
-
56
- Teammates can own separate end-to-end work packages or hand over the same package. Product, full-stack, and testing are AI perspectives each teammate may use (review is the Run's built-in read-only reviewer, not a session perspective); both the person and the perspective can change. Access control relies on existing repository hosting, execution platforms, and team authorization agreements. BuildBeat does not add a member account or permission system.
57
-
58
- ## Changing tools, models, and perspectives
59
-
60
- Project artifacts are readable files that different tools can consume. The new tool needs the entry point, access to the same project, and suitable permissions. Execution Workers also need a compatible command, authentication, and output contract. The external AI tool selects the model.
61
-
62
- The product, full-stack, and testing perspectives read the same Work's goal, constraints, and evidence, and follow their own write boundaries; review is carried out by the Run's built-in read-only reviewer. Changing perspective does not change accepted scope or require duplicating progress documents. The current runtime supports one active Run per repository.
63
-
64
- This explains protocol continuity, not proof that every tool combination has passed a real handoff. See the [capability matrix](../../CAPABILITY-MATRIX.md) for existing evidence and the [adapter guide](04-adapter-guide.md) for integration requirements (Chinese).
65
-
66
- ## Moving machines versus recovering a Run
67
-
68
- | Retained or synchronized content | What it supports | What it does not establish |
69
- |---|---|---|
70
- | Committed Work artifacts, decisions, standards, and terminal records | Reading durable project facts on another machine | Raw execution logs and active checkpoints were also synchronized |
71
- | Candidate branches and their commits | Reading candidate code, diffs, and merge status | An ordinary clone fetched a branch that exists only on the old machine |
72
- | Local runtime and the matching worktree | Inspecting and recovering an active Run in its original environment | Copying files to another path migrates an executing process |
73
-
74
- `.buildbeat/runtime/` contains active ledgers and raw logs; `.buildbeat/worktrees/` contains working trees. Both are normally excluded from Git. After runtime cleanup, Git-managed facts can support further project work, but exact active-Run recovery and raw logs are no longer assured. A terminal record's log digest cannot reconstruct the log text.
75
-
76
- To take over elsewhere, synchronize project facts and candidates, prepare tools and environment, and decide where execution should resume. BuildBeat does not currently automate active-Run migration between machines.
77
-
78
- ## Verifying a real handoff
79
-
80
- Choose a small task with an existing verification command. Session A saves a goal and plan, then executes to an identifiable state. Record the Work, candidate, verification result, and pending decision. Close the chat. Give a fresh session B only the project location and a request to continue, without the old conversation history. For a team handoff, have another authorized teammate sync the files and candidate, then perform this step using their own tool.
81
-
82
- Check whether B reads the same goal, state, and next step from project files and tools, then continues within existing authorization. Record tool and model versions, files read, actual commands, and the outcome. Verify combinations of tools, teammates, and machines individually. An illustrative conversation is not that evidence.
83
-
84
- Existing `tests/v2-resume.test.js`, `tests/v2-approval.test.js`, and `tests/v2-overview-stages.test.js` cover recovery and state mechanisms. They do not constitute model-behavior acceptance for a real fresh-session handoff.
19
+ A handoff example does not establish every tool combination as verified.
@@ -1,84 +1,19 @@
1
- # 跨会话接续:关掉聊天,保留工作
1
+ # 跨会话接续
2
2
 
3
- **简体中文** | [English](11-session-handoff.en.md)
3
+ [English](11-session-handoff.en.md)
4
4
 
5
- BuildBeat 的接续依据是项目文件、Git 与运行台账。新会话读取这些事实后,判断继续执行、恢复中断、处理待批,还是开始同一 Work 的下一次 Run。接手的人可以是自己,也可以是另一位团队成员。接手不需要旧聊天全文,也不会自动保存只存在于聊天中的讨论。
5
+ 关闭旧会话前,将目标、决定、未验证范围和下一步写入项目;检查 Git、候选与运行状态。保留活动 Run 的台账和工作树。
6
6
 
7
- ## 关闭旧会话前
7
+ 新会话读取项目 AGENTS.md、Work 的 work.md(或旧 intent/plan)、决定与 status。能从记录查到的事实自行核对,沿用仍有效的授权;不把开新会话等同于重开 Run。
8
8
 
9
- 在当前会话中说:
9
+ 主仓管理多个代码仓时,先运行 `buildbeat status --repo . --all-repos`。它只读查看主仓、主仓 `delivery/work/` 下 run 配置的 `repo:` 目标仓,以及主仓下一层含 `delivery/work/` 的 Git 仓,按真实路径去重,不递归。不存在或无效的目标、读不了的配置会给出警告,其余仓继续显示。
10
10
 
11
- > 我要换会话。把继续工作必需、但还只在聊天里的上下文落到项目文件,核对当前 Work、候选、未验证事项、待批和运行状态。
11
+ 待人决定先列出,随后按仓显示未了结工作;CLOSED、CANCELLED 和已合并且配置没有 `release:` 的工作只计数。已合并但配有 `release:`、尚未关窗的工作仍显示。`--json` 返回 `{repos: [{repo, works, settled}], pending, warnings}`,包含已了结工作;`--work <ID>` 筛选各仓合并后的这项工作,`--run` 不能与 `--all-repos` 同用。
12
12
 
13
- 会话应完成这些核对:
13
+ 主仓配置指向的代码仓已有同名工作目录或运行台账时,状态、审查问题和决定取自代码仓,只在代码仓下显示;提示命令保留主仓配置,仓路径和配置路径相对当前目录,可填入人名、理由等占位内容后执行。目标仓还没有记录时,工作留在主仓并注明运行目标。不加 `--all-repos` 的主仓 `status` 也会读取这一层目标仓的真实状态,避免提示重复开跑。
14
14
 
15
- - 目标、范围、验收条件与决定已有明确文件落点;补录事实时不改写既有批准,也不把未接受的想法写成已接受计划。
16
- - 候选提交、工作树中的未提交改动、测试证据与下一步可定位;关键环境事实写入 Work 的 `env-facts.md`,秘密只标来源,不写入项目记录。
17
- - 使用 `overview` / `inbox` / `status` 读回实况。若 Run 还在执行,说明进程是否脱离驾驶会话;无法确认就说明不确定。
18
- - 需要跨机器或共享时,按已有授权提交、同步相关项目文件和候选分支;写到磁盘不等于已提交或已推送。
15
+ 换工具时重新配置命令、鉴权和输出合同;接手事实可以复用,具体工具执行能力需要验证。换人时同步候选、记录和权限,说明当前推进人及下一步。
19
16
 
20
- 这些事实已落盘时,无需为每次换会话另写一篇长交接报告。关闭或删除聊天应只处理聊天记录,保留项目目录、运行台账与工作树;某些工具会连同临时工作区一起清理,先核对其实际范围。
17
+ 换机器只能通过 Git 同步长期事实。活动进程、运行时文件、工作树和宿主资源不会随 clone 迁移,先核对原环境再选择接手方式。
21
18
 
22
- ## 新会话如何接手
23
-
24
- 在**同一项目目录**打开新会话,按所用工具的方式加载 BuildBeat Skill 和项目 `AGENTS.md`,然后说:
25
-
26
- > 继续这个项目。先读 BuildBeat 入口和当前工作项,核对 Git、进度、验证结果和待批事项,再在已有授权范围内继续。
27
-
28
- 会话先读当前事实:
29
-
30
- ```bash
31
- buildbeat overview --repo .
32
- buildbeat inbox --repo .
33
- ```
34
-
35
- 随后读取对应 `delivery/work/<ID>/` 的目标、计划、决定和配置;需要活动 Run 细节时运行 `status --repo . --run <RUN-ID>`。ID 从实际输出读取,不凭聊天猜。
36
-
37
- | 读到的情况 | 下一步 |
38
- |---|---|
39
- | Run 仍在正常执行 | 继续观察,避免启动重复 Run 或改它的工作树 |
40
- | Run 等人决定 | 展示当前待批对象与证据;新会话不会自动继承一份不存在或已过期的批准 |
41
- | Runner 中断,运行台账和工作树仍在 | 按恢复手册核对现场,再 `resume --config <配置路径>`;中断步可能重跑 |
42
- | 工作树脏、配置改变、批准失效或现场缺失 | 说明具体差异,按运行时要求处理,不能声称已无损恢复 |
43
- | Run 已终结,Work 还需后续执行 | 基于现有工件和候选准备下一次 Run;终态 Run 不重新打开 |
44
- | 工作已经合并或发布 | 回读相应 Git 或发布事实,避免因某次旧 Run 被取消而重复执行 |
45
-
46
- 恢复批准与最终合并决定是不同动作。详见 [批准指南](07-approval-guide.md) 和 [故障恢复](10-recovery.md)。
47
-
48
- ## 另一位团队成员接手
49
-
50
- 交出方将需要共享的目标、计划、决定、验收记录和下一步落到项目文件,按已有授权同步到共享仓库,并使候选提交可达。在 Work 的项目记录中说明当前由谁继续推进、原 Run 是否仍在执行及所在环境;运行状态仍以实际回读为准。
51
-
52
- 接手方取得项目访问权限后,同步相应文件和候选分支,加载项目入口,用自己的 AI 工具核对范围、证据、待批事项与环境。仍然有效的既有决定继续保留;接手不会自动获得他人的合并、发布或凭据权限。
53
-
54
- 若原 Run 尚未终结,先核对原执行环境。新机器的 `overview` 或 `inbox` 没有活动项,不代表旧机器没有活动 Run。本地锁不会协调不同机器或 Git 副本,不能据此重复启动同一份工作。需要在新环境重新执行时,先明确原 Run 的处置,再从已同步工件与候选准备后续 Run。
55
-
56
- 团队成员可以按端到端工作包分工,也可以交接同一个包。产品、全栈、测试是各成员可调用的 AI 视角(审查是 Run 内置的只读 reviewer,不是会话视角),具体接手的人与视角可以变化。访问控制依赖已有 Git 托管、执行平台和团队授权约定,BuildBeat 不另建成员账号或权限系统。
57
-
58
- ## 换工具、模型和角色
59
-
60
- 项目工件是可读文件,可由不同工具消费。新工具需要加载入口、具备必要权限并能读到同一项目;执行 Worker 还需满足命令、鉴权与输出合同。模型由外部 AI 工具选择。
61
-
62
- 产品、全栈、测试三个视角都读同一个 Work 的目标、约束与证据,按各自写入边界接手;审查由 Run 内置的只读 reviewer 承担。换视角不改变已经接受的范围,不需要把同一套事实复制成多份进度文档。当前一仓仅支持一个活动 Run。
63
-
64
- 这说明协议如何接续,不代表任意工具组合都已通过真实接力验证。已有工具证据见 [能力矩阵](../../CAPABILITY-MATRIX.md),接入要求见 [Adapter 指南](04-adapter-guide.md)。
65
-
66
- ## 换机器与运行恢复的区别
67
-
68
- | 保留或同步的内容 | 能支撑什么 | 不能直接推出什么 |
69
- |---|---|---|
70
- | 已提交的 Work、决定、规范与终态记录 | 新机器读取长期项目事实 | 原始运行日志与活动检查点也已同步 |
71
- | 候选分支及其提交 | 读取候选代码,核对差异与合并状态 | 普通 clone 已取到仅存在于旧机器上的分支 |
72
- | 本机 runtime 与对应 worktree | 在原环境核对并恢复活动 Run | 拷文件到任意路径即可迁移正在执行的进程 |
73
-
74
- `.buildbeat/runtime/` 保存活动台账和原始日志,`.buildbeat/worktrees/` 保存工作树,通常均排除在 Git 之外。清理 runtime 后可依据 Git 面继续项目工作,但活动 Run 的精确恢复与原始日志不再保证。终态记录中的日志 digest 也不能还原日志正文。
75
-
76
- 跨地点接手时,先同步项目事实和候选,准备工具与环境,再决定从何处执行。BuildBeat 当前不提供活动 Run 的自动跨机器迁移。
77
-
78
- ## 怎样验证一次真实接力
79
-
80
- 选一个已有验证命令的小任务。会话 A 将目标与计划落盘并执行到可识别的状态;记录 Work、候选、验证结果与待批对象。关闭旧聊天,在不携带旧聊天历史的新会话 B 中只提供项目位置和接续请求。团队场景由另一位有权限的成员同步文件和候选后,用自己的工具执行这一步。
81
-
82
- 核对 B 是否能从文件和工具回读出同样的目标、状态与下一步,并在现有授权内继续。记录工具和模型版本、读取的文件、实际命令与最后结果。跨工具、跨成员或跨机器时,每种组合分别记录;演示对话不能替代这份证据。
83
-
84
- 现有 `tests/v2-resume.test.js`、`tests/v2-approval.test.js` 与 `tests/v2-overview-stages.test.js` 覆盖恢复和状态判断机制;它们不等于真实新会话接手的模型行为验收。
19
+ 跨会话演示不等于所有工具组合都已验证。
@@ -0,0 +1,46 @@
1
+ # Taking part without the runtime
2
+
3
+ [简体中文](12-without-runtime.md)
4
+
5
+ People and AI tools without the `buildbeat` runtime (a machine without Node, a web AI chat, a locked-down company computer) can still take part through the project files. They have no automatic loop, isolated worktree, approval checks, budgets or recovery, and must not claim them.
6
+
7
+ ## What you can read
8
+
9
+ | File (under `delivery/work/<ID>/`) | Content |
10
+ |---|---|
11
+ | `work.md` | Goal, scope, acceptance, implementation plan |
12
+ | `decisions.jsonl` | Acceptances, approvals, closures; one JSON object per line |
13
+ | `review-findings.jsonl` | Review findings and human verdicts |
14
+ | `runs/<RUN>/run-record.json` | Terminal state, candidate, evidence digests and cost of finished runs |
15
+ | `releases.jsonl` | Release readbacks after the merge |
16
+
17
+ The ledger of a run in progress lives in `.buildbeat/runtime/` on the machine running it and is not in Git; that side's `buildbeat status` is authoritative for progress.
18
+
19
+ ## What you can write
20
+
21
+ - **Draft or edit `work.md`.** An edit invalidates the existing acceptance; the runtime shows it as awaiting acceptance or stale.
22
+ - **Accept `work.md` as the work owner:** append a line to `decisions.jsonl`. `digest` is the SHA-256 of the `work.md` file content (for example `shasum -a 256 work.md`); `decisionRef` is `A-<ID>-<current line count + 1>`:
23
+
24
+ ```json
25
+ {"ts":"2026-10-04T08:00:00.000Z","decisionRef":"A-WORK-X-1","decision":"approved","transition":"accept-work","subject":{"artifact":"work","digest":"sha256:<64 hex digits>"},"by":"<name>"}
26
+ ```
27
+
28
+ - **Rule on a recorded review finding:** append a line to `review-findings.jsonl`. `fingerprint` must be an existing finding's fingerprint; `action` is `accept` or `dismiss`:
29
+
30
+ ```json
31
+ {"ts":"2026-10-04T08:00:00.000Z","kind":"adjudication","fingerprint":"<fingerprint>","action":"dismiss","by":"<name>","note":"<reason>"}
32
+ ```
33
+
34
+ - **Close a Work that needs no release** (for example a documentation change): append `{"ts":"2026-10-04T09:00:00.000Z","decision":"closed","transition":"close-work","subject":{"result":"<outcome>"},"by":"<name>"}`. A Work that is released closes through the runtime's `release` and `decide --action close`, which bind the closure to a readback.
35
+
36
+ Each line must be one complete JSON object; only append, never edit earlier lines. Commit the files and hand them to someone with the runtime.
37
+
38
+ ## What you must not do
39
+
40
+ - Approve or reject a run, or adopt a candidate: the runtime records these in the run ledger and re-reads the candidate and evidence before stamping.
41
+ - Write or edit a run ledger, `run-record.json`, `releases.jsonl` or any evidence; claim that verification, review or a release readback has passed.
42
+ - Record a decision in someone else's name, or edit existing lines.
43
+
44
+ ## Handing over to someone with the runtime
45
+
46
+ After pulling the commit they run `buildbeat status --repo . --work <ID>`: a changed `work.md` shows as awaiting acceptance, and hand-written acceptance and adjudication lines take effect under the same digest and fingerprint rules. `buildbeat run --config <config>` then continues delivery.