repo-harness 0.15.2 → 0.16.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 (67) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/README.es.md +2 -2
  4. package/README.fr.md +2 -2
  5. package/README.ja.md +2 -2
  6. package/README.md +2 -2
  7. package/README.zh-CN.md +2 -2
  8. package/agents/fleet/harness-evaluator.md +1 -1
  9. package/assets/reference-configs/minimal-change-hooks.md +42 -7
  10. package/assets/reference-configs/sprint-contracts.md +12 -0
  11. package/assets/skill-version.json +10 -2
  12. package/assets/skills/obsidian-memory/SKILL.md +29 -18
  13. package/assets/skills/repo-harness-product/references/sprint.md +1 -1
  14. package/assets/templates/helpers/check-architecture-sync.sh +18 -7
  15. package/assets/templates/helpers/contract-worktree.sh +286 -21
  16. package/assets/templates/helpers/ensure-task-workflow.sh +1 -1
  17. package/assets/templates/helpers/ship-worktrees.sh +21 -3
  18. package/assets/templates/helpers/sprint-backlog.sh +359 -85
  19. package/assets/templates/helpers/verify-sprint.sh +230 -24
  20. package/assets/templates/helpers/worktree-merge-lib.sh +105 -0
  21. package/assets/workflow-contract.v1.json +2 -0
  22. package/dist/hook-entry.js +3666 -2557
  23. package/package.json +4 -3
  24. package/scripts/axr5-archctx-clean-room.ts +1 -1
  25. package/scripts/axr6-stop-host-cycle.ts +6 -6
  26. package/scripts/axr7-consumer-e2e.ts +2 -2
  27. package/scripts/check-architecture-sync.sh +18 -7
  28. package/scripts/contract-worktree.sh +286 -21
  29. package/scripts/ensure-task-workflow.sh +1 -1
  30. package/scripts/lib/project-init-lib.sh +1 -1
  31. package/scripts/run-debug-ground-truth-eval.ts +633 -0
  32. package/scripts/setup-plugins.sh +4 -4
  33. package/scripts/ship-worktrees.sh +21 -3
  34. package/scripts/sprint-backlog.sh +359 -85
  35. package/scripts/verify-sprint.sh +230 -24
  36. package/scripts/worktree-merge-lib.sh +105 -0
  37. package/src/cli/commands/init.ts +52 -0
  38. package/src/cli/commands/sprint.ts +803 -0
  39. package/src/cli/commands/state.ts +86 -0
  40. package/src/cli/hook/board-slice-context.ts +184 -0
  41. package/src/cli/hook/circuit-breaker.ts +4 -1
  42. package/src/cli/hook/event-telemetry.ts +17 -0
  43. package/src/cli/hook/minimal-change-policy.ts +9 -14
  44. package/src/cli/hook/mutation-guard.ts +217 -0
  45. package/src/cli/hook/runtime.ts +18 -15
  46. package/src/cli/hook/session-context.ts +234 -1
  47. package/src/cli/hook/stop-handler.ts +181 -7
  48. package/src/cli/hook/subagent-handler.ts +62 -6
  49. package/src/cli/index.ts +2 -0
  50. package/src/cli/installer/install-profile.ts +1 -4
  51. package/src/core/architecture/projection.ts +2 -2
  52. package/src/core/state/coordination-identity.ts +579 -0
  53. package/src/core/state/project-board-slice.ts +129 -0
  54. package/src/core/state/project-board.ts +393 -0
  55. package/src/core/state/project-continuation-envelope.ts +33 -30
  56. package/src/core/state/sprint-backlog-rows.ts +53 -0
  57. package/src/core/state/types.ts +215 -0
  58. package/src/effects/git/worktree-topology.ts +100 -0
  59. package/src/effects/locking/exclusive-directory-lock.ts +34 -3
  60. package/src/effects/state/collect-board-inputs.ts +255 -0
  61. package/src/effects/state/collect-slice-inputs.ts +123 -0
  62. package/src/effects/state/coordination-canonical-source.ts +89 -0
  63. package/src/effects/state/coordination-claim-token.ts +133 -0
  64. package/src/effects/state/coordination-cutover.ts +308 -0
  65. package/src/effects/state/coordination-lease-store.ts +366 -0
  66. package/src/effects/state/resolve-board.ts +64 -0
  67. package/src/effects/state/resolve-effective-state.ts +15 -2
package/AGENTS.md CHANGED
@@ -31,7 +31,7 @@ This repository self-hosts the `repo-harness` contract; the former `repo-harness
31
31
  - Keep `CLAUDE.md` and `AGENTS.md` short; put detailed guidance in `docs/reference-configs/`.
32
32
  - Treat Codex auto-compact as a fallback only; use `.ai/harness/handoff/current.md` and `.ai/harness/handoff/resume.md` for long-task rollover.
33
33
  - Treat `.ai/harness/checks/*.latest.{json,md}` and `.ai/harness/runs/` as ignored runtime evidence cache; commit durable conclusions in `tasks/reviews/`, `tasks/contracts/`, `tasks/notes/`, or `docs/researches/` instead.
34
- - Treat architecture/spec/research docs as the human reading entrypoint. Before closing a workflow, promote durable conclusions into `docs/architecture/`, `docs/researches/`, `docs/spec.md`, or `tasks/lessons.md`; then archive fulfilled plan/contract/review/notes/todo artifacts so root workflow surfaces represent active work only. `.rgignore` hides archived workflow artifacts and runtime evidence from default `rg` searches; use explicit paths or `rg -uu` for audits.
34
+ - Treat architecture/spec/research docs as the human reading entrypoint. Before closing a workflow, promote durable conclusions into `docs/architecture/`, `docs/researches/`, `docs/spec.md`, or `tasks/lessons.md`; then archive fulfilled plan/contract/review/notes/todo artifacts so root workflow surfaces represent active work only. When a brain root is configured, a durable conclusion worth reusing across projects may additionally be projected into the vault through an explicit `obsidian-memory` persist call; the vault layer is optional and never a prerequisite for closing a workflow. `.rgignore` hides archived workflow artifacts and runtime evidence from default `rg` searches; use explicit paths or `rg -uu` for audits.
35
35
  - Treat `_ref/` as an occasional ignored external reference checkout cache, not a commit surface or daily workflow. Agents may read or refresh it for comparison; when it influences a decision, cite the source repo plus commit/tag and path in `tasks/notes/` or `docs/researches/`.
36
36
  - Treat `deploy/` as the trackable deployment and operations surface for runbooks, submission materials, release checklists, helper scripts, ordered SQL files, and env examples; follow `.ai/harness/policy.json#operations.deploy_sql` for configured SQL roots and naming modes, otherwise keep SQL directly under `deploy/sql/` with 4-digit ascending prefixes.
37
37
  - Treat `_ops/` as ignored local operations state for secrets, real env files, provider state, artifacts, logs, and scratch files; do not commit or agent-edit `_ops/*`.
package/CLAUDE.md CHANGED
@@ -31,7 +31,7 @@ This repository self-hosts the `repo-harness` contract; the former `repo-harness
31
31
  - Keep `CLAUDE.md` and `AGENTS.md` short; put detailed guidance in `docs/reference-configs/`.
32
32
  - Treat Codex auto-compact as a fallback only; use `.ai/harness/handoff/current.md` and `.ai/harness/handoff/resume.md` for long-task rollover.
33
33
  - Treat `.ai/harness/checks/*.latest.{json,md}` and `.ai/harness/runs/` as ignored runtime evidence cache; commit durable conclusions in `tasks/reviews/`, `tasks/contracts/`, `tasks/notes/`, or `docs/researches/` instead.
34
- - Treat architecture/spec/research docs as the human reading entrypoint. Before closing a workflow, promote durable conclusions into `docs/architecture/`, `docs/researches/`, `docs/spec.md`, or `tasks/lessons.md`; then archive fulfilled plan/contract/review/notes/todo artifacts so root workflow surfaces represent active work only. `.rgignore` hides archived workflow artifacts and runtime evidence from default `rg` searches; use explicit paths or `rg -uu` for audits.
34
+ - Treat architecture/spec/research docs as the human reading entrypoint. Before closing a workflow, promote durable conclusions into `docs/architecture/`, `docs/researches/`, `docs/spec.md`, or `tasks/lessons.md`; then archive fulfilled plan/contract/review/notes/todo artifacts so root workflow surfaces represent active work only. When a brain root is configured, a durable conclusion worth reusing across projects may additionally be projected into the vault through an explicit `obsidian-memory` persist call; the vault layer is optional and never a prerequisite for closing a workflow. `.rgignore` hides archived workflow artifacts and runtime evidence from default `rg` searches; use explicit paths or `rg -uu` for audits.
35
35
  - Treat `_ref/` as an occasional ignored external reference checkout cache, not a commit surface or daily workflow. Agents may read or refresh it for comparison; when it influences a decision, cite the source repo plus commit/tag and path in `tasks/notes/` or `docs/researches/`.
36
36
  - Treat `deploy/` as the trackable deployment and operations surface for runbooks, submission materials, release checklists, helper scripts, ordered SQL files, and env examples; follow `.ai/harness/policy.json#operations.deploy_sql` for configured SQL roots and naming modes, otherwise keep SQL directly under `deploy/sql/` with 4-digit ascending prefixes.
37
37
  - Treat `_ops/` as ignored local operations state for secrets, real env files, provider state, artifacts, logs, and scratch files; do not commit or agent-edit `_ops/*`.
package/README.es.md CHANGED
@@ -467,8 +467,8 @@ repositorio adopte la misma política.
467
467
 
468
468
  ## Versión actual
469
469
 
470
- - Paquete npm: `repo-harness@0.15.2`
471
- - Sello de workflow generado: `repo-harness@0.15.2+template@0.15.2`
470
+ - Paquete npm: `repo-harness@0.16.0`
471
+ - Sello de workflow generado: `repo-harness@0.16.0+template@0.16.0`
472
472
  - Repositorio de GitHub: `Ancienttwo/repo-harness`
473
473
  - Notas de versión e historial: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
474
474
 
package/README.fr.md CHANGED
@@ -462,8 +462,8 @@ adopte la même policy.
462
462
 
463
463
  ## Release actuelle
464
464
 
465
- - Package npm : `repo-harness@0.15.2`
466
- - Generated workflow stamp : `repo-harness@0.15.2+template@0.15.2`
465
+ - Package npm : `repo-harness@0.16.0`
466
+ - Generated workflow stamp : `repo-harness@0.16.0+template@0.16.0`
467
467
  - Dépôt GitHub : `Ancienttwo/repo-harness`
468
468
  - Notes et historique de release : [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
469
469
 
package/README.ja.md CHANGED
@@ -470,8 +470,8 @@ commit script や hooks に組み込まないでください。
470
470
 
471
471
  ## 現在の Release
472
472
 
473
- - npm package:`repo-harness@0.15.2`
474
- - Generated workflow stamp:`repo-harness@0.15.2+template@0.15.2`
473
+ - npm package:`repo-harness@0.16.0`
474
+ - Generated workflow stamp:`repo-harness@0.16.0+template@0.16.0`
475
475
  - GitHub repository:`Ancienttwo/repo-harness`
476
476
  - Release notes and history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
477
477
 
package/README.md CHANGED
@@ -442,8 +442,8 @@ repo-harness commit scripts or hooks unless that repo adopts the same policy.
442
442
 
443
443
  ## Current Release
444
444
 
445
- - npm package: `repo-harness@0.15.2`
446
- - Generated workflow stamp: `repo-harness@0.15.2+template@0.15.2`
445
+ - npm package: `repo-harness@0.16.0`
446
+ - Generated workflow stamp: `repo-harness@0.16.0+template@0.16.0`
447
447
  - GitHub repository: `Ancienttwo/repo-harness`
448
448
  - Release notes and history: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
449
449
 
package/README.zh-CN.md CHANGED
@@ -449,8 +449,8 @@ policy。
449
449
 
450
450
  ## 当前 Release
451
451
 
452
- - npm package:`repo-harness@0.15.2`
453
- - Generated workflow stamp:`repo-harness@0.15.2+template@0.15.2`
452
+ - npm package:`repo-harness@0.16.0`
453
+ - Generated workflow stamp:`repo-harness@0.16.0+template@0.16.0`
454
454
  - GitHub repository:`Ancienttwo/repo-harness`
455
455
  - Release notes 和 history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
456
456
 
@@ -9,7 +9,7 @@ effort: high
9
9
  You are the disposable-state evaluator of existing repo-harness behavior. The orchestrator gives you a subject revision, baseline, profile, and complete disposable repo/HOME; you invoke existing evaluation surfaces there and report. You never create a new evaluator, grading method, dataset, truth source, or product gate.
10
10
 
11
11
  - **Verdict first.** Open with exactly one of `EVAL: PASS`, `EVAL: REGRESSION`, `EVAL: INCONCLUSIVE`, or `EVAL: BLOCKED`. PASS requires the named cases and both subject/baseline evidence when comparison is requested. REGRESSION requires a concrete behavioral delta. INCONCLUSIVE names missing or ambiguous evidence. BLOCKED names the environment, permission, or profile boundary that prevented execution.
12
- - **Choose one declared profile.** `skills` uses the existing skill-eval manifest, runner, graders, and tests. A full benchmark must use a disposable clone/worktree and invoke `bun scripts/run-skill-evals.ts --require-disposable --repo <disposable-repo> --home <disposable-home> ...`; guarded mode places its workspace under the disposable repo even though the ordinary benchmark default is a sibling directory. `adoption` must invoke `bun scripts/run-skill-evals.ts --run-adoption-profile --repo <disposable-repo> --home <disposable-home>`; that single guarded command injects the validated repo/HOME into the existing project-state inspector and `init --dry-run --json`. Both modes scrub inherited repo-harness source/helper overrides before spawning commands. Existing migration/audit fixtures may be cited as read-only context but are not separately executed with writable authority. The repo and HOME must be sibling directories under one disposable parent. Never omit the profile's guard or run against the source checkout. Migration auditing is this profile, not another identity.
12
+ - **Choose one declared profile.** `skills` uses the existing skill-eval manifest, runner, graders, and tests. A full benchmark must use a disposable clone/worktree and invoke `bun scripts/run-skill-evals.ts --require-disposable --repo <disposable-repo> --home <disposable-home> ...`; guarded mode places its workspace under the disposable repo even though the ordinary benchmark default is a sibling directory. `adoption` must invoke `bun scripts/run-skill-evals.ts --run-adoption-profile --repo <disposable-repo> --home <disposable-home>`; that single guarded command injects the validated repo/HOME into the existing project-state inspector and `init --dry-run --json`. `debug-ground-truth` invokes `bun run benchmark:debug -- --provider stub` from the disposable repository; this is a trusted in-process self-test, not a live or untrusted-provider isolation claim. The runner, rather than this evaluator, owns its fixture copy, hidden truth, fresh replay, and report. Do not open, paraphrase, or pass `evals/debug-hunt/ground-truth.json` to another model; report only the runner's typed result and provenance. Both modes scrub inherited repo-harness source/helper overrides before spawning commands. Existing migration/audit fixtures may be cited as read-only context but are not separately executed with writable authority. The repo and HOME must be sibling directories under one disposable parent. Never omit the profile's guard or run against the source checkout. Migration auditing is this profile, not another identity.
13
13
  - **Workspace-write is disposable-only.** Before any write-producing command, verify that both the working repository and HOME are the orchestrator-provided disposable locations and that the dispatch names them explicitly. Supplying only a temporary workspace directory is insufficient when a runner writes elsewhere in its repository. If the complete disposable repo/HOME is absent, ambiguous, or resolves to the source checkout or real HOME, return BLOCKED.
14
14
  - **BDD2 is forbidden authority.** Never read, invoke, modify, score, or cite `evals/bdd2/**` or `scripts/run-bdd2-evals.ts`. If a contract requests either path, fail closed and return it to the parent; that sealed system has its own runner, truth, and review authority.
15
15
  - **Remain a judge.** Inside disposable state, allow only writes produced by the existing evaluator/adoption commands. Do not hand-edit source, fixtures, manifests, graders, reports, policy, agent definitions, or benchmark methodology. Do not commit, push, open or merge PRs, mutate real HOME, publish, apply adoption, or repair findings. The orchestrator prepares disposable state and assigns fixes.
@@ -2,8 +2,9 @@
2
2
 
3
3
  Minimal-change hooks keep large or risky edits visible without turning the hook
4
4
  runtime into an implementation policy engine. Repos that do not declare
5
- `minimal_change` policy stay off by default; enabled policy remains advisory and
6
- fail-open.
5
+ `minimal_change` policy stay off by default, and `mode: "advice"` stays
6
+ advisory and fail-open. A repo opts into blocking explicitly with
7
+ `mode: "enforce"`, which arms one Stop gate and nothing else.
7
8
 
8
9
  ## Runtime Path
9
10
 
@@ -20,8 +21,9 @@ fail-open.
20
21
  deterministic report to `.ai/harness/checks/minimal-change.latest.json`.
21
22
  - `Stop.default` runs the in-process `src/cli/hook/stop-handler.ts`. Stop
22
23
  review reads the canonical latest report for diagnostics and block-reason
23
- suffixes without rewriting the recovery handoff. It does not block the
24
- session by itself.
24
+ suffixes without rewriting the recovery handoff. Under `mode: "advice"` it
25
+ does not block the session by itself; under `mode: "enforce"` it runs the
26
+ enforce gate described below.
25
27
 
26
28
  ## Policy
27
29
 
@@ -56,9 +58,42 @@ The policy lives at `.ai/harness/policy.json` under `minimal_change`:
56
58
 
57
59
  Missing or malformed policy disables the layer. `mode: "off"` also disables it.
58
60
  `mode: "advice"` enables advisory context and Stop review; the post-edit
59
- observer stays opt-in through `post_edit_observer: true`. `mode: "enforce"` is
60
- treated as advisory behavior in this layer, so minimal-change findings never
61
- become a host-level block.
61
+ observer stays opt-in through `post_edit_observer: true`. `mode: "enforce"`
62
+ keeps every advice-mode behavior and additionally arms the Stop enforce gate.
63
+ An unknown mode fails closed to `off`. `mode` is the single source of truth:
64
+ `enforce` is the only blocking mode, and there is no separate blocking knob.
65
+
66
+ ## Enforce Gate
67
+
68
+ Under `mode: "enforce"`, Stop blocks when the latest report verdict is
69
+ `review` and no matching audit receipt exists. The block reason lists the
70
+ findings and restates the receipt contract, so it stays self-contained.
71
+
72
+ The receipt lives at `.ai/harness/checks/minimal-change-audit.latest.json`:
73
+
74
+ ```json
75
+ {
76
+ "version": 1,
77
+ "fingerprint": "<the audited report's fingerprint>",
78
+ "decisions": ["one non-empty decision per finding"],
79
+ "generated_at": "2026-08-17T21:30:00.000Z"
80
+ }
81
+ ```
82
+
83
+ `fingerprint` must equal the audited report's `fingerprint` exactly. A missing,
84
+ malformed, or mismatched receipt releases nothing: the gate stays closed. Like
85
+ the report, the receipt is runtime evidence under `.ai/harness/` and is never
86
+ committed.
87
+
88
+ The gate is bounded by the shared circuit breaker
89
+ (`.ai/harness/state/circuit-breaker.json`, kind `minimal-change`), keyed per
90
+ report fingerprint: at most two blocks for the same fingerprint, after which
91
+ Stop is released with a warning instead of blocking. A new report fingerprint
92
+ is real progress and resets the counter.
93
+
94
+ Enforce is per-repo opt-in. The shipped defaults stay `mode: "advice"` with
95
+ `post_edit_observer: false`, and setting `mode` back to `"advice"` restores
96
+ advisory-only behavior with no other change.
62
97
 
63
98
  ## Report Contract
64
99
 
@@ -137,6 +137,18 @@ acceptance can validate, even if the movement is otherwise non-overlapping.
137
137
 
138
138
  `verify-contract.sh --read-only` is read-only for contract state writes only: it does not rewrite the contract `> **Status**:` line. It executes `tests_pass` with Bun and `commands_succeed` in a non-login Bash with `BASH_ENV` unset. One fixed absolute 600-second budget covers the whole invocation; each command records duration, exit status, signal, and timeout state, and expiry terminates the command's process group before the verifier returns. The budget is not a policy or environment knob.
139
139
 
140
+ ### Long Gate Commands Belong to the Orchestrator
141
+
142
+ The same 600-second ceiling applies to the host stream watchdog that kills a
143
+ delegated agent after 600 seconds of silence. Any gate command expected to
144
+ exceed roughly five minutes (`verify-sprint`, a full `bun test`) is run by the
145
+ orchestrator's main loop in the background, not foreground-waited inside a
146
+ dispatched worker. An agent handed such a command names the command and returns
147
+ BLOCKED on its role's machine-readable first line (`RESULT:` / `VERDICT:` /
148
+ `RECOMMENDATION:`), handing control back; it does not stand watch. The
149
+ standing advisory is injected at SubagentStart under the
150
+ `[repo-harness:long-command-guardrail]` marker.
151
+
140
152
  Verification is an evidence consumer. `commands_succeed` must not launch profile benchmarks/providers, `init`, evidence-producer scripts, or substantive installs; the verifier rejects those command shapes before execution. Produce expensive evidence explicitly, validate its subject/provenance/bytes, then let `verify-sprint` consume that frozen artifact through `verify-contract --read-only`.
141
153
 
142
154
  A verifier consumes already-produced evidence; it must not become the producer of expensive, runtime-heavy evidence (for example, a full multi-provider/multi-profile benchmark matrix). An authoritative matrix or similarly expensive one-time evidence run belongs outside `commands_succeed`: the author runs it once on a clean checkout before merge and commits the resulting tracked report (for example `evals/harness/reports/profile-comparison.json`/`.md`); the contract then verifies that report's bytes and provenance, not a live re-run.
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.15.2",
3
- "templateVersion": "0.15.2",
2
+ "version": "0.16.0",
3
+ "templateVersion": "0.16.0",
4
4
  "skillName": "repo-harness",
5
5
  "contractId": "tasks-first-harness-v1",
6
6
  "compatibility": {
@@ -247,6 +247,14 @@
247
247
  {
248
248
  "version": "0.15.2",
249
249
  "description": "Syncs archctx 0.4.3 with docs-renderer v3 so canonical-body-digest restamp churn stops, adds the repo-owned obsidian-memory dual-host skill facade with a runtime-referenced official Obsidian skills declaration, strips machine node-runtime authority from faked CLI test environments, and resolves archctx from the target repo before the CLI root so architecture projection drain no longer blocks after a global refresh"
250
+ },
251
+ {
252
+ "version": "0.15.3",
253
+ "description": "Lands the shared coordination plane WP1 as a common-dir lease store behind the sprint verbs claim, bind, release, steal, reconcile, identify, and begin-completion with a quiescent fail-closed cutover; hardens the lease protocol with a three-field owner record, a completing-state guard, an inline complete gate, fail-closed rejection of legacy lease shapes, and a fixed marker write order; pins archctx 0.4.4 with the archcontext.docs-renderer/v4 projection contract; adds a SubagentStart long-command guardrail advisory and a SessionStart cleanable-contract-worktree notice; makes CodeGraph enablement explicit opt-in only; adds minimal_change enforce mode behind a Stop gate and circuit breaker; and collapses worktree base metadata onto one typed, fail-closed selector"
254
+ },
255
+ {
256
+ "version": "0.16.0",
257
+ "description": "Completes the kanban coordination program on top of the 0.15.3 lease plane: adds the deterministic board projection `state board --json` emitting the frozen BoardDocumentV1 with four precedence-ordered columns, three separated dimensions, per-dimension and composite input revisions, and a stable | changed_during_read snapshot-consistency verdict from a single-retry collector; adds a bind-time resumed receipt so a steal-then-rebind no longer inherits the previous claim's no-progress receipts; injects a byte-identical read-only BoardSliceV1 at Codex SubagentStart context and the Claude PreToolUse.subagent Task|Agent branch through one pure projector and one shared renderer; arms a PreToolUse.edit lease gate only behind the double predicate of a unique claim token matching the active-plan marker and a linked worktree, failing closed with an explicit reason token per step while leaving non-sprint execution untouched; and retires the merged worktree at the tail of contract-worktree finish --merge"
250
258
  }
251
259
  ],
252
260
  "generatedProjectStamp": {
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: obsidian-memory
3
3
  description: |
4
- Cross-project long-term memory over the user's Obsidian brain vault: recall relevant
4
+ Cross-project long-term memory over an Obsidian brain vault: recall relevant
5
5
  notes before a task, and persist distilled conclusions (decisions, pitfalls, solutions,
6
- progress) back after a task. The vault is an aggregation/projection layer — repo-local
7
- artifacts stay the per-project source of truth, and sync direction is repo → brain.
8
- Explicitly invoked by the model or operator; never executed from hooks. Use when the
9
- user asks to recall project memory, persist lessons to Obsidian, initialize a project
10
- sub-vault, or when closing a significant task whose conclusions are worth keeping.
6
+ progress) back after a task. The vault is an optional aggregation/projection layer —
7
+ repo-local artifacts stay the per-project source of truth, and sync direction is
8
+ repo → brain. Explicitly invoked by the model or operator; never executed from hooks.
9
+ Use when the user asks to recall project memory, persist lessons to Obsidian, initialize
10
+ a project sub-vault, or when closing a significant task whose conclusions are worth keeping.
11
11
  Triggers: 检索记忆, 查一下知识库, 沉淀经验, 记到 Obsidian, 更新知识库, 复盘沉淀,
12
12
  初始化记忆库, recall project memory, persist lessons, update the brain vault,
13
13
  knowledge base brain. Do not use for repo-runtime contracts (tasks/, docs/ stay
@@ -24,18 +24,20 @@ description: |
24
24
  - 双读者: vault 的读者是 agent **和用户本人**。笔记必须是人能直接阅读学习的成文——完整句子、讲清 why 与 tradeoff,不写 agent 速记、不堆原始日志;`index.md` 是人的阅读入口。
25
25
  - 边界: 本 skill 只能由模型或用户显式调用。hooks 永不执行它——hook 层最多发 `[BrainPromote]` 类建议文本,不读写 vault 状态。
26
26
 
27
- ## Vault 解析(fail-closed)
27
+ ## Vault 解析(fail-closed,且 vault 本身是可选的)
28
28
 
29
29
  1. 读 `~/.repo-harness/config.json` 的 `brainRoot`。
30
- 2. 缺失或路径不存在 → 停止并告知用户配置(`repo-harness update --brain-root <path>` 或手改 config),**不扫描磁盘猜 vault、不临时新建 vault root**。
30
+ 2. 未配置或路径不存在 → **停止并说明**,不扫描磁盘猜 vault、不临时新建 vault root。
31
31
  3. 项目 sub-vault 为 `<brainRoot>/<project-slug>/`;`<project-slug>` 取 repo 目录名或用户指定名。
32
32
 
33
+ **没有配置 brainRoot 是一个合法的稳态,不是待修复的故障。** 未配置就意味着这台机器不使用 vault 层:repo 内 artifact 依然是完整可用的权威记忆,收口时把结论写进 `tasks/lessons.md`、`docs/researches/` 等既有槽位即可,不要为了让本 skill 能跑而去创建 vault。仅当用户明确表示要启用 vault 层时,才指路 `repo-harness install --brain-root <path>` 或 `repo-harness update --brain-root <path>`。
34
+
33
35
  ## Phase init · 建立项目 sub-vault
34
36
 
35
37
  仅在 sub-vault 不存在或用户明确要求时执行:
36
38
 
37
- 1. 创建 `<brainRoot>/<project-slug>/`,内含 `index.md` 与按需的 `decisions/`、`patterns/`、`references/`、`runbooks/`(对齐 vault 既有分类,不发明新分类学)。
38
- 2. `index.md` 记项目一句话背景、长期偏好、当前进度指针、各子目录链接;用 wiki-link 挂进 vault 根 `index.md` 的 Domains 列表。
39
+ 1. 创建 `<brainRoot>/<project-slug>/`,内含 `index.md` 与按需的 `decisions/`、`patterns/`、`notes/`、`references/`、`runbooks/`(对齐 vault 既有分类,不发明新分类学)。
40
+ 2. `index.md` 记项目一句话背景、长期偏好、当前进度指针、各子目录链接;用 wiki-link 挂进 vault 根 `index.md`。
39
41
  3. **依赖官方 Obsidian skills(硬依赖)**:任何创建或修改 vault 内 `.md` 的动作必须同时调用官方 `obsidian-markdown` skill(frontmatter、wiki-links、callouts 等格式权威);需要对运行中 vault 做搜索/打开/任务操作时用官方 `obsidian-cli` skill。本 skill 只负责判断与索引(写什么、何时写、如何组织),不自定 Markdown 方言。两个官方 skill 缺失时 fail-closed 报告,不降级手写格式。
40
42
 
41
43
  ## Phase recall · 任务前召回
@@ -47,18 +49,24 @@ description: |
47
49
  ## Phase persist · 任务后沉淀
48
50
 
49
51
  1. 提取候选:关键决策及理由、踩坑根因与解法、可复用方案/模式、失败方案及拒因、进度里程碑。
50
- 2. **价值闸门**——同时满足才写:未来会再用到(对 agent 复用或对用户学习二者居其一即可);不是 repo artifact 已记录内容的复述(已有的写一行 wiki-link 指回 repo 路径,不复制正文);不是一次性/临时信息。
51
- 3. **敏感闸门**——写盘前扫描内容:密码、API key、token、私钥、真实 env 值一律不落 vault;命中即改写为占位符或放弃该条。
52
- 4. 写入对应子目录并更新 sub-vault `index.md`;同类主题已有笔记则更新原文件,不另开重复页;发现过时结论直接改掉。
53
- 5. 在 repo-harness 管理的仓库里,`docs/reference-configs/` 类文档的外化走既有 `repo-harness brain promote`/`sync` 通道,本 skill 不与其重复搬运。
52
+ 2. **排除式写入门槛(先过这一条)**——凡是 git、包管理 registry、代码托管平台、CI 或任一可重跑命令已经权威记录的事实,vault 只写指针,不写正文。据此明确排除:commit SHA、PR/issue 编号、merge commit、CI run ID、tag、release URL、`main == origin/main == <sha>` 之类的同步状态、worktree 干净与否、测试通过计数、某次命令的快照输出。这些写下去那一刻就开始腐烂,而且原本就有权威源。
53
+ 3. **价值闸门**——过了排除规则后还要同时满足:未来会再用到(对 agent 复用或对用户学习二者居其一即可);不是 repo artifact 已记录内容的复述(已有的写一行 wiki-link 指回 repo 路径,不复制正文);不是一次性/临时信息。
54
+ 4. **敏感闸门**——写盘前扫描内容:密码、API key、token、私钥、真实 env 值一律不落 vault;命中即改写为占位符或放弃该条。
55
+ 5. **绝对路径慎写**——机器改名、家目录迁移、checkout 位置变化都会让硬编码路径静默失效。能写 repo 相对路径或让工具自行解析根路径的,就不要写绝对路径。
56
+ 6. 写入对应子目录并更新 sub-vault `index.md`;同类主题已有笔记则更新原文件,不另开重复页;发现过时结论直接改掉。
57
+
58
+ ## 目录所有权边界
59
+
60
+ 在 repo-harness 管理的仓库里,`.ai/harness/brain-manifest.json` 声明的 `brain_path` 是 `repo-harness brain sync` 的**机器投影**,手写内容会被下次 sync 覆盖。本 skill 永远不写 manifest 声明过的路径;记忆笔记落在 `notes/`、`decisions/` 这类 manifest 不拥有的子目录。`docs/reference-configs/` 类文档的外化走既有 `brain promote`/`sync` 通道,本 skill 不与其重复搬运。
54
61
 
55
62
  ## 与既有记忆层的分工
56
63
 
57
64
  | 层 | 归属 | 存什么 |
58
65
  |----|------|--------|
59
66
  | repo `tasks/lessons.md`、`docs/researches/`、`MEMORY.md` | 各项目 source of truth | 项目内可执行的规则与知识 |
60
- | `~/.claude/memory/`、`GLOBAL.md` | 会话运行时记忆 | 用户偏好、跨项目工作规律 |
61
- | Obsidian vault(本 skill) | 跨项目聚合投影 | 蒸馏后的决策/模式/坑/进度,供人和多 runtime 复用 |
67
+ | host 自动记忆(Claude Code project memory、Codex chronicle 等) | session 级运行时缓存 | 当轮上下文;**不得引用为事实**,有长期价值的先 promote 到权威层 |
68
+ | 用户级跨项目偏好文件 | 跨项目偏好 source of truth | 用户习惯、跨项目通用坑、工具偏好 |
69
+ | Obsidian vault(本 skill) | 可选的跨项目聚合投影 | 蒸馏后的决策/模式/坑/进度,供人和多 runtime 复用 |
62
70
 
63
71
  同一事实只在权威层写正文,其余层写指针。
64
72
 
@@ -67,13 +75,16 @@ description: |
67
75
  | 情况 | 规则 |
68
76
  |------|------|
69
77
  | 想在 hook 里自动触发 | 禁止;hook 只发建议文本,沉淀由模型在收尾流程显式调用 |
70
- | brainRoot 未配置 | fail-closed 停止并指路,不猜路径 |
78
+ | brainRoot 未配置 | 合法稳态;报告后停止,不猜路径、不代建 vault |
71
79
  | 记忆与现状矛盾 | 现状赢;修正或删除过时笔记 |
72
- | 每轮任务都想写一笔 | 只沉淀过价值闸门的内容;无货则明说本轮无可沉淀 |
80
+ | 每轮任务都想写一笔 | 只沉淀过闸门的内容;无货则明说本轮无可沉淀 |
73
81
  | 大段对话/代码想整段存档 | 不存原文,存结论 + 指回 repo 的链接 |
82
+ | 想把验收报告贴进来 | CI run、commit、PR、release 状态一律只写指针 |
74
83
  | 含敏感值的配置经验 | 用 `<PLACEHOLDER>` 改写后再存 |
84
+ | 声称「已接入某处」 | 当场 grep 目标文件验证;只存在于文档里的接线等于没有接线 |
75
85
 
76
86
  ## Provenance
77
87
 
78
88
  - 2026-08-16 由用户的「Obsidian 作为跨项目 AI 知识库大脑」提案落地;经评审否决 hook 实现路线,采用 skill + 显式收口,对齐 repo-harness `brain-manifest.json` 的既有 invariant(hooks 不读写外部 vault 状态)。
89
+ - 2026-08-18 修订:加入排除式写入门槛与 manifest 目录所有权边界,并把 vault 层明确为可选——未配置 brainRoot 时 repo 内 artifact 独立成立,不再把「没有 vault」当成待修复状态。
79
90
  - 双侧安装:`~/.claude/skills/obsidian-memory/` 与 `~/.codex/skills/obsidian-memory/` 内容一致,用 `cmp` 校验。
@@ -26,7 +26,7 @@ when present.
26
26
  - Treat the row as a long-task waypoint, not a detailed implementation plan.
27
27
  - For `contract` rows, invoke `$think` with the sprint path, row task, mode, acceptance line, and Promotion Gate fields so the coding agent expands it into a decision-complete plan. Capture the approved `$think` output with `repo-harness run capture-plan --artifact-level work-package --promotion-reason worktree_boundary --source waza-think --source-ref sprint:<sprint-file>#<task> --status Approved --execute`.
28
28
  - For `inline` rows, do not create a new `plans/plan-*.md` or task contract. Keep the work in the sprint backlog or the current active plan's `## Task Breakdown`, then complete the row when the acceptance line is verified.
29
- - `repo-harness run sprint-backlog start-task` remains a compatibility helper for reserving a row. It captures a thin plan seed only for `contract` rows; inline rows append checklist-row content to the current active plan before recording an in-flight marker.
29
+ - `repo-harness run sprint-backlog start-task --task <index|task>` claims the named pending row on the shared coordination plane before any capture runs. `--task` is required: the backlog carries no dependency or parallel-safety column, so there is no automatic claim-next and the caller names the row. It captures a thin plan seed only for `contract` rows; inline rows append checklist-row content to the current active plan.
30
30
  - Execute contract slices as usual (implement, `/check`, external acceptance, `repo-harness run contract-worktree finish`); finish back-fills the backlog row warn-only.
31
31
  4. Route `status`: report `repo-harness run sprint-backlog status` plus the Active Sprint section of `tasks/current.md`; mutate nothing.
32
32
  5. After each completed task, re-read the sprint file before starting the next one; user edits to the backlog override stale session memory.
@@ -262,6 +262,17 @@ projection_blocking=$((projection_pending + projection_running + projection_dead
262
262
  if [[ "$projection_provider" == "archctx" && "$projection_state" != "ready" ]]; then
263
263
  projection_blocking=$((projection_blocking + 1))
264
264
  fi
265
+ # Reported, never gated: the Stop drain applies projections into the worktree
266
+ # but nothing commits them, so the restamp backlog only surfaces when a human
267
+ # happens to read the diff. Counting it here names the backlog at its own
268
+ # check surface instead of leaving it to be rediscovered in an unrelated turn.
269
+ # A non-git checkout has no "uncommitted" concept, so 0 is the accurate count
270
+ # there rather than a stand-in for an unavailable value.
271
+ projection_uncommitted=0
272
+ if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
273
+ projection_uncommitted="$(git status --porcelain -- docs/architecture 2>/dev/null | sed '/^$/d' | wc -l | tr -d ' ' || true)"
274
+ : "${projection_uncommitted:=0}"
275
+ fi
265
276
 
266
277
  case "$mode" in
267
278
  off|advisory|strict) ;;
@@ -312,8 +323,8 @@ fi
312
323
 
313
324
  if [[ "$mode" == "off" ]]; then
314
325
  case "$format" in
315
- json) printf '{"mode":"off","changed_capabilities":0,"blocking":0,"projection":{"provider":"%s","apply":"%s","state":"%s","pending":%s,"running":%s,"dead_letters":%s,"human_actions":%s,"adoption_required":%s,"blocking":%s}}\n' "$(json_escape "$projection_provider")" "$(json_escape "$projection_apply")" "$(json_escape "$projection_state")" "$projection_pending" "$projection_running" "$projection_dead_letters" "$projection_human_actions" "$projection_adoption_required" "$projection_blocking" ;;
316
- text) echo "[ArchitectureSync] mode=off changed_capabilities=0 blocking=0"; echo "[ArchitectureProjection] provider=$projection_provider apply=$projection_apply state=$projection_state pending=$projection_pending running=$projection_running dead_letters=$projection_dead_letters human_actions=$projection_human_actions adoption_required=$projection_adoption_required blocking=$projection_blocking" ;;
326
+ json) printf '{"mode":"off","changed_capabilities":0,"blocking":0,"projection":{"provider":"%s","apply":"%s","state":"%s","pending":%s,"running":%s,"dead_letters":%s,"human_actions":%s,"adoption_required":%s,"blocking":%s,"uncommitted":%s}}\n' "$(json_escape "$projection_provider")" "$(json_escape "$projection_apply")" "$(json_escape "$projection_state")" "$projection_pending" "$projection_running" "$projection_dead_letters" "$projection_human_actions" "$projection_adoption_required" "$projection_blocking" "$projection_uncommitted" ;;
327
+ text) echo "[ArchitectureSync] mode=off changed_capabilities=0 blocking=0"; echo "[ArchitectureProjection] provider=$projection_provider apply=$projection_apply state=$projection_state pending=$projection_pending running=$projection_running dead_letters=$projection_dead_letters human_actions=$projection_human_actions adoption_required=$projection_adoption_required blocking=$projection_blocking uncommitted=$projection_uncommitted" ;;
317
328
  *) echo "check-architecture-sync: unsupported --format: $format" >&2; exit 2 ;;
318
329
  esac
319
330
  exit 0
@@ -331,8 +342,8 @@ fi
331
342
  changed_files="$(collect_changed_files | sort -u)"
332
343
  if [[ -z "$changed_files" ]]; then
333
344
  case "$format" in
334
- json) printf '{"mode":"%s","gate_min_severity":"%s","changed_capabilities":0,"blocking":0,"projection":{"provider":"%s","apply":"%s","state":"%s","reason":"%s","pending":%s,"running":%s,"dead_letters":%s,"human_actions":%s,"adoption_required":%s,"blocking":%s}}\n' "$(json_escape "$mode")" "$(json_escape "$threshold")" "$(json_escape "$projection_provider")" "$(json_escape "$projection_apply")" "$(json_escape "$projection_state")" "$(json_escape "$projection_reason")" "$projection_pending" "$projection_running" "$projection_dead_letters" "$projection_human_actions" "$projection_adoption_required" "$projection_blocking" ;;
335
- text) echo "[ArchitectureSync] mode=$mode gate_min_severity=$threshold changed_capabilities=0 blocking=0"; echo "[ArchitectureProjection] provider=$projection_provider apply=$projection_apply state=$projection_state pending=$projection_pending running=$projection_running dead_letters=$projection_dead_letters human_actions=$projection_human_actions adoption_required=$projection_adoption_required blocking=$projection_blocking" ;;
345
+ json) printf '{"mode":"%s","gate_min_severity":"%s","changed_capabilities":0,"blocking":0,"projection":{"provider":"%s","apply":"%s","state":"%s","reason":"%s","pending":%s,"running":%s,"dead_letters":%s,"human_actions":%s,"adoption_required":%s,"blocking":%s,"uncommitted":%s}}\n' "$(json_escape "$mode")" "$(json_escape "$threshold")" "$(json_escape "$projection_provider")" "$(json_escape "$projection_apply")" "$(json_escape "$projection_state")" "$(json_escape "$projection_reason")" "$projection_pending" "$projection_running" "$projection_dead_letters" "$projection_human_actions" "$projection_adoption_required" "$projection_blocking" "$projection_uncommitted" ;;
346
+ text) echo "[ArchitectureSync] mode=$mode gate_min_severity=$threshold changed_capabilities=0 blocking=0"; echo "[ArchitectureProjection] provider=$projection_provider apply=$projection_apply state=$projection_state pending=$projection_pending running=$projection_running dead_letters=$projection_dead_letters human_actions=$projection_human_actions adoption_required=$projection_adoption_required blocking=$projection_blocking uncommitted=$projection_uncommitted" ;;
336
347
  *) echo "check-architecture-sync: unsupported --format: $format" >&2; exit 2 ;;
337
348
  esac
338
349
  exit 0
@@ -362,12 +373,12 @@ case "$format" in
362
373
  blocking_json="$(
363
374
  printf '%s\n' "$blocking_lines" | awk -F '\t' 'NF >= 3 { printf "%s{\"capability_id\":\"%s\",\"severity\":\"%s\",\"request\":\"%s\"}", sep, $1, $2, $3; sep="," }'
364
375
  )"
365
- printf '{"mode":"%s","gate_min_severity":"%s","changed_capabilities":%s,"blocking":%s,"blocking_requests":[%s],"projection":{"provider":"%s","apply":"%s","state":"%s","reason":"%s","pending":%s,"running":%s,"dead_letters":%s,"human_actions":%s,"adoption_required":%s,"blocking":%s}}\n' \
366
- "$(json_escape "$mode")" "$(json_escape "$threshold")" "$changed_count" "$blocking_count" "$blocking_json" "$(json_escape "$projection_provider")" "$(json_escape "$projection_apply")" "$(json_escape "$projection_state")" "$(json_escape "$projection_reason")" "$projection_pending" "$projection_running" "$projection_dead_letters" "$projection_human_actions" "$projection_adoption_required" "$projection_blocking"
376
+ printf '{"mode":"%s","gate_min_severity":"%s","changed_capabilities":%s,"blocking":%s,"blocking_requests":[%s],"projection":{"provider":"%s","apply":"%s","state":"%s","reason":"%s","pending":%s,"running":%s,"dead_letters":%s,"human_actions":%s,"adoption_required":%s,"blocking":%s,"uncommitted":%s}}\n' \
377
+ "$(json_escape "$mode")" "$(json_escape "$threshold")" "$changed_count" "$blocking_count" "$blocking_json" "$(json_escape "$projection_provider")" "$(json_escape "$projection_apply")" "$(json_escape "$projection_state")" "$(json_escape "$projection_reason")" "$projection_pending" "$projection_running" "$projection_dead_letters" "$projection_human_actions" "$projection_adoption_required" "$projection_blocking" "$projection_uncommitted"
367
378
  ;;
368
379
  text)
369
380
  echo "[ArchitectureSync] mode=$mode gate_min_severity=$threshold changed_capabilities=$changed_count blocking=$blocking_count"
370
- echo "[ArchitectureProjection] provider=$projection_provider apply=$projection_apply state=$projection_state pending=$projection_pending running=$projection_running dead_letters=$projection_dead_letters human_actions=$projection_human_actions adoption_required=$projection_adoption_required blocking=$projection_blocking"
381
+ echo "[ArchitectureProjection] provider=$projection_provider apply=$projection_apply state=$projection_state pending=$projection_pending running=$projection_running dead_letters=$projection_dead_letters human_actions=$projection_human_actions adoption_required=$projection_adoption_required blocking=$projection_blocking uncommitted=$projection_uncommitted"
371
382
  if [[ "$blocking_count" -gt 0 ]]; then
372
383
  printf '%s\n' "$blocking_lines" | while IFS=$'\t' read -r capability severity request; do
373
384
  [[ -n "$capability" ]] || continue