repo-harness 0.16.0 → 0.16.2

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 (76) hide show
  1. package/AGENTS.md +2 -2
  2. package/CLAUDE.md +2 -2
  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 +13 -5
  7. package/README.zh-CN.md +13 -5
  8. package/assets/partials/03-philosophy.partial.md +6 -0
  9. package/assets/partials-agents/04-task-protocol.partial.md +0 -1
  10. package/assets/partials-agents/06-quality-safety.partial.md +1 -0
  11. package/assets/reference-configs/external-tooling.md +45 -9
  12. package/assets/reference-configs/global-working-rules.md +8 -0
  13. package/assets/reference-configs/sprint-contracts.md +2 -0
  14. package/assets/skill-commands/manifest.json +40 -1
  15. package/assets/skill-version.json +10 -2
  16. package/assets/templates/helpers/acceptance-receipt.ts +78 -4
  17. package/assets/templates/helpers/architecture-event.ts +22 -5
  18. package/assets/templates/helpers/check-agent-tooling.sh +102 -19
  19. package/assets/templates/helpers/contract-worktree.sh +210 -37
  20. package/assets/templates/helpers/ensure-task-workflow.sh +1 -0
  21. package/assets/templates/helpers/install-agent-fleet.sh +6 -15
  22. package/assets/templates/helpers/merge-gate.ts +79 -26
  23. package/assets/templates/helpers/ship-worktrees.sh +28 -10
  24. package/assets/templates/helpers/sprint-backlog.sh +63 -2
  25. package/assets/templates/helpers/verify-contract.sh +1 -1
  26. package/assets/templates/helpers/verify-sprint.sh +105 -8
  27. package/dist/hook-entry.js +582 -287
  28. package/package.json +5 -5
  29. package/scripts/acceptance-receipt.ts +78 -4
  30. package/scripts/architecture-event.ts +22 -5
  31. package/scripts/check-agent-tooling.sh +102 -19
  32. package/scripts/contract-worktree.sh +210 -37
  33. package/scripts/ensure-task-workflow.sh +1 -0
  34. package/scripts/install-agent-fleet.sh +6 -15
  35. package/scripts/lib/project-init-lib.sh +1 -0
  36. package/scripts/merge-gate.ts +79 -26
  37. package/scripts/run-skill-hook.ts +16 -1
  38. package/scripts/ship-worktrees.sh +28 -10
  39. package/scripts/sprint-backlog.sh +63 -2
  40. package/scripts/verify-contract.sh +1 -1
  41. package/scripts/verify-sprint.sh +105 -8
  42. package/src/cli/commands/architecture-projection.ts +23 -0
  43. package/src/cli/commands/cross-review.ts +101 -1
  44. package/src/cli/commands/global-runtime.ts +189 -29
  45. package/src/cli/commands/init-hook.ts +4 -0
  46. package/src/cli/commands/init.ts +21 -8
  47. package/src/cli/commands/mcp.ts +12 -6
  48. package/src/cli/commands/run.ts +113 -3
  49. package/src/cli/commands/sprint.ts +77 -2
  50. package/src/cli/hook/architecture-drift.ts +64 -0
  51. package/src/cli/hook/circuit-breaker.ts +2 -1
  52. package/src/cli/hook/stop-handler.ts +16 -0
  53. package/src/cli/hook/subagent-handler.ts +109 -49
  54. package/src/cli/index.ts +19 -4
  55. package/src/cli/installer/install-profile.ts +22 -1
  56. package/src/cli/mcp/coding-tools.ts +9 -1
  57. package/src/cli/mcp/coding-workspaces.ts +210 -22
  58. package/src/cli/mcp/guarded-write.ts +192 -0
  59. package/src/cli/mcp/setup.ts +16 -1
  60. package/src/cli/mcp/tools.ts +92 -20
  61. package/src/cli/mcp/transports/http.ts +54 -21
  62. package/src/cli/runtime/helper-runner.ts +73 -86
  63. package/src/cli/runtime/protected-helper-platform.ts +469 -0
  64. package/src/cli/tools/codegraph.ts +36 -0
  65. package/src/core/adoption/standard-plan.ts +8 -0
  66. package/src/core/architecture/restamp-publication.ts +90 -0
  67. package/src/core/review/cross-review.ts +11 -3
  68. package/src/core/skill-surface/catalog.ts +149 -0
  69. package/src/core/state/coordination-identity.ts +47 -0
  70. package/src/effects/architecture/archctx-provider.ts +33 -3
  71. package/src/effects/architecture/projection-jobs.ts +23 -0
  72. package/src/effects/architecture/restamp-publication.ts +264 -0
  73. package/src/effects/process-runner.ts +14 -8
  74. package/src/effects/process-supervisor.ts +19 -16
  75. package/src/effects/review/cross-review-runner.ts +14 -0
  76. package/src/effects/runtime/node-candidates.ts +48 -0
package/AGENTS.md CHANGED
@@ -36,7 +36,7 @@ This repository self-hosts the `repo-harness` contract; the former `repo-harness
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/*`.
38
38
  - Treat contract-level task execution as worktree-first: `repo-harness run plan-to-todo --plan <approved-plan>` starts `repo-harness run contract-worktree start --plan <approved-plan>` when policy enables it, and completed blocks finish through Waza `/check` plus `repo-harness run contract-worktree finish`.
39
- - Treat the EXECUTION_BOUNDARY anti-extras clause as mandatory on every delegated runner surface (contract worker prompts, the Codex delegation advisor hook, subagent start context, and MCP `codex-goal` documents): absent requirements are forbidden design space, not permission to improve, and unrequested extras fail closed.
39
+ - Treat the EXECUTION_BOUNDARY anti-extras clause as mandatory exactly once in each delegated runner's final rendered task packet: absent requirements are forbidden design space, not permission to improve, and unrequested extras fail closed. Each runner path names one injection owner and no other surface on that path may carry the clause — the Codex native-child path is owned by `SubagentStart.context` (contract- and writability-aware; generated personas and the delegation advisor carry none), the standalone contract worker path by its worker prompt, and the MCP path by the `codex-goal` document. Composed-path tests verify the count.
40
40
  - After Codex Plan mode, Waza `/think`, or `repo-harness-plan` produces a decision-complete work-package plan, capture it with `repo-harness run capture-plan --artifact-level work-package --slug <slug> --title <title>` so `plans/` becomes the file-backed source of truth; if the user has already approved implementation, capture with `--status Approved --execute --promotion-reason <merge_boundary|rollback_boundary|verification_boundary|risk_boundary|human_decision_boundary|worktree_boundary>` or run `repo-harness run plan-to-todo --plan <active-plan>`.
41
41
  - Promote work into a top-level `plans/plan-*.md` only when `Artifact Level: work-package` is justified by a merge/PR unit, rollback surface, independent verification boundary, review/acceptance boundary, high-risk surface, or otherwise cannot remain a checklist item in the current active plan or sprint backlog. Inline sprint rows and checklist rows stay in the sprint backlog or active plan `## Task Breakdown`; contract rows may expand into plan -> contract -> review -> notes only through the work-package gate.
42
42
  - If current repo state conflicts with the task, open an isolated `codex/<task-slug>` worktree, finish there, run Waza `/check`-style validation, then merge back to `main` without absorbing unrelated dirty changes.
@@ -59,7 +59,7 @@ This repository self-hosts the `repo-harness` contract; the former `repo-harness
59
59
  ## Required Checks
60
60
 
61
61
  ```bash
62
- bun test
62
+ bun test --timeout 60000
63
63
  bash scripts/check-deploy-sql-order.sh
64
64
  bash scripts/check-architecture-sync.sh
65
65
  bash scripts/check-task-sync.sh
package/CLAUDE.md CHANGED
@@ -36,7 +36,7 @@ This repository self-hosts the `repo-harness` contract; the former `repo-harness
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/*`.
38
38
  - Treat contract-level task execution as worktree-first: `repo-harness run plan-to-todo --plan <approved-plan>` starts `repo-harness run contract-worktree start --plan <approved-plan>` when policy enables it, and completed blocks finish through Waza `/check` plus `repo-harness run contract-worktree finish`.
39
- - Treat the EXECUTION_BOUNDARY anti-extras clause as mandatory on every delegated runner surface (contract worker prompts, the Codex delegation advisor hook, subagent start context, and MCP `codex-goal` documents): absent requirements are forbidden design space, not permission to improve, and unrequested extras fail closed.
39
+ - Treat the EXECUTION_BOUNDARY anti-extras clause as mandatory exactly once in each delegated runner's final rendered task packet: absent requirements are forbidden design space, not permission to improve, and unrequested extras fail closed. Each runner path names one injection owner and no other surface on that path may carry the clause — the Codex native-child path is owned by `SubagentStart.context` (contract- and writability-aware; generated personas and the delegation advisor carry none), the standalone contract worker path by its worker prompt, and the MCP path by the `codex-goal` document. Composed-path tests verify the count.
40
40
  - After Codex Plan mode, Waza `/think`, or `repo-harness-plan` produces a decision-complete work-package plan, capture it with `repo-harness run capture-plan --artifact-level work-package --slug <slug> --title <title>` so `plans/` becomes the file-backed source of truth; if the user has already approved implementation, capture with `--status Approved --execute --promotion-reason <merge_boundary|rollback_boundary|verification_boundary|risk_boundary|human_decision_boundary|worktree_boundary>` or run `repo-harness run plan-to-todo --plan <active-plan>`.
41
41
  - Promote work into a top-level `plans/plan-*.md` only when `Artifact Level: work-package` is justified by a merge/PR unit, rollback surface, independent verification boundary, review/acceptance boundary, high-risk surface, or otherwise cannot remain a checklist item in the current active plan or sprint backlog. Inline sprint rows and checklist rows stay in the sprint backlog or active plan `## Task Breakdown`; contract rows may expand into plan -> contract -> review -> notes only through the work-package gate.
42
42
  - If current repo state conflicts with the task, open an isolated `codex/<task-slug>` worktree, finish there, run Waza `/check`-style validation, then merge back to `main` without absorbing unrelated dirty changes.
@@ -59,7 +59,7 @@ This repository self-hosts the `repo-harness` contract; the former `repo-harness
59
59
  ## Required Checks
60
60
 
61
61
  ```bash
62
- bun test
62
+ bun test --timeout 60000
63
63
  bash scripts/check-deploy-sql-order.sh
64
64
  bash scripts/check-architecture-sync.sh
65
65
  bash scripts/check-task-sync.sh
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.16.0`
471
- - Sello de workflow generado: `repo-harness@0.16.0+template@0.16.0`
470
+ - Paquete npm: `repo-harness@0.16.2`
471
+ - Sello de workflow generado: `repo-harness@0.16.2+template@0.16.2`
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.16.0`
466
- - Generated workflow stamp : `repo-harness@0.16.0+template@0.16.0`
465
+ - Package npm : `repo-harness@0.16.2`
466
+ - Generated workflow stamp : `repo-harness@0.16.2+template@0.16.2`
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.16.0`
474
- - Generated workflow stamp:`repo-harness@0.16.0+template@0.16.0`
473
+ - npm package:`repo-harness@0.16.2`
474
+ - Generated workflow stamp:`repo-harness@0.16.2+template@0.16.2`
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
@@ -41,9 +41,10 @@ with a tasks-first agent contract that keeps Claude and Codex aligned.
41
41
 
42
42
  ### 1. Install the CLI
43
43
 
44
- Prerequisites: a Git working tree, `bash`, and `bun`; `jq` is optional. No
45
- Node.js required — the installer uses Bun >= 1.1.35 as the runtime, installing or
46
- upgrading Bun first when needed.
44
+ Prerequisites: a Git working tree and `bun`; macOS/Linux also require `bash`,
45
+ while Windows requires Git for Windows (including its Bash and `usr/bin`
46
+ tools). `jq` is optional. No Node.js required — the installer uses Bun >=
47
+ 1.1.35 as the runtime, installing or upgrading Bun first when needed.
47
48
 
48
49
  ```bash
49
50
  # macOS / Linux
@@ -70,6 +71,13 @@ npx -y repo-harness@latest install # npx fallback; the CLI still runs on Bun
70
71
  repo-harness install
71
72
  ```
72
73
 
74
+ On Windows, keep Git for Windows on the install/update `PATH`. That explicit
75
+ ceremony validates and pins `git.exe`, its matching `bash.exe`/`usr/bin`, and
76
+ the install account's absolute `TEMP` directory plus native `System32` tools in the OS account's
77
+ `~/.repo-harness/config.json#protectedHelperRuntime`. Protected workflow
78
+ helpers do not rediscover tools from a caller's `PATH`; rerun
79
+ `repo-harness update` after relocating or replacing Git for Windows.
80
+
73
81
  The global bootstrap: installs the npm package as the global CLI, refreshes
74
82
  repo-harness skill aliases, installs user-level hook adapters, and records an
75
83
  explicit install profile. It is idempotent and does not apply repo-local workflow
@@ -442,8 +450,8 @@ repo-harness commit scripts or hooks unless that repo adopts the same policy.
442
450
 
443
451
  ## Current Release
444
452
 
445
- - npm package: `repo-harness@0.16.0`
446
- - Generated workflow stamp: `repo-harness@0.16.0+template@0.16.0`
453
+ - npm package: `repo-harness@0.16.2`
454
+ - Generated workflow stamp: `repo-harness@0.16.2+template@0.16.2`
447
455
  - GitHub repository: `Ancienttwo/repo-harness`
448
456
  - Release notes and history: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
449
457
 
package/README.zh-CN.md CHANGED
@@ -41,9 +41,10 @@ checks 和 review evidence 写回项目文件,让下一个 agent 会话从文
41
41
 
42
42
  ### 1. 安装 CLI
43
43
 
44
- 前置条件:一个 Git working tree、`bash` 和 `bun`;`jq` 可选。不需要
45
- Node.js——installer 使用 Bun >= 1.1.35 作为 runtime,需要时会先安装或升级
46
- Bun。
44
+ 前置条件:一个 Git working tree 和 `bun`;macOS/Linux 还需要 `bash`,
45
+ Windows 则需要 Git for Windows(包括其 Bash 与 `usr/bin` 工具)。`jq`
46
+ 可选。不需要 Node.js——installer 使用 Bun >= 1.1.35 作为 runtime,需要时会
47
+ 先安装或升级 Bun。
47
48
 
48
49
  ```bash
49
50
  # macOS / Linux
@@ -70,6 +71,13 @@ npx -y repo-harness@latest install # npx fallback; the CLI still runs on Bun
70
71
  repo-harness install
71
72
  ```
72
73
 
74
+ Windows 上应在执行 install/update 时让 Git for Windows 位于 `PATH`。
75
+ 这次显式配置会验证 `git.exe`、同一安装根下的 `bash.exe`/`usr/bin` 以及原生
76
+ `System32` 工具和安装账号的绝对 `TEMP` 目录,并将这些路径固定到 OS 账号的
77
+ `~/.repo-harness/config.json#protectedHelperRuntime`。protected workflow
78
+ helper 运行时不会再从调用者 `PATH` 搜索工具;Git for Windows 被移动或替换
79
+ 后,必须重新运行 `repo-harness update`。
80
+
73
81
  这个全局 bootstrap 会把 npm 包安装成全局 CLI,刷新 repo-harness 的 skill
74
82
  aliases,安装 user-level hook adapters,并记录一份明确的 install profile。
75
83
  它是幂等的,不会把 repo-local workflow 文件应用到当前目录。`--dry-run
@@ -449,8 +457,8 @@ policy。
449
457
 
450
458
  ## 当前 Release
451
459
 
452
- - npm package:`repo-harness@0.16.0`
453
- - Generated workflow stamp:`repo-harness@0.16.0+template@0.16.0`
460
+ - npm package:`repo-harness@0.16.2`
461
+ - Generated workflow stamp:`repo-harness@0.16.2+template@0.16.2`
454
462
  - GitHub repository:`Ancienttwo/repo-harness`
455
463
  - Release notes 和 history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
456
464
 
@@ -24,6 +24,12 @@ BUG_FIX_FLOW:
24
24
  3. Re-run full verification
25
25
  ```
26
26
 
27
+ #### Artifact Hygiene
28
+
29
+ - Write comments, commit messages, and PR text from the final diff only, as if discarded intermediate attempts never existed.
30
+ - Comments state only the non-obvious reason at the owning boundary; never restate the operation, preserve intermediate attempts, or list speculative future work.
31
+ - PR text states final behavior plus only the material rationale or trade-off a reviewer cannot recover from the diff; never mention never-merged states or reverted work.
32
+
27
33
  Detailed playbooks:
28
34
  - `docs/reference-configs/harness-overview.md`
29
35
  - `docs/reference-configs/agentic-development-flow.md`
@@ -53,7 +53,6 @@ RULES:
53
53
  - Promote factors only after hypothesis and backtest summary artifacts exist
54
54
  - Run the configured factor-lab check before claiming factor-lab work is complete
55
55
  {{/IF}}
56
-
57
56
  ACTIVE_PLAN:
58
57
  - .ai/harness/active-plan selects the current active plan only for its owning worktree; .ai/harness/active-worktree records that owner
59
58
 
@@ -12,6 +12,7 @@
12
12
  - Do not silently expand scope beyond approved plan.
13
13
  - If unexpected repo changes appear, stop and ask.
14
14
  - Prefer modifying existing files over unnecessary file creation.
15
+ - Write comments, commit messages, and PR text from the final diff only: comments state only the non-obvious reason at the owning boundary; PR text states final behavior plus only rationale a reviewer cannot recover from the diff; never mention discarded attempts, reverted work, or never-merged states.
15
16
 
16
17
  ### Final Response Contract
17
18
  1. What changed — list modified files with one-line summary each
@@ -224,7 +224,7 @@ boundary explicit:
224
224
  | Capability | Owner | Required for |
225
225
  |---|---|---|
226
226
  | `bun` | repo-harness | repo-harness-owned global installs, local dependency install, tests, and runtime execution |
227
- | `bash` | repo-harness | helper scripts, migration, setup checks, and contract verification wrappers |
227
+ | `bash` | repo-harness | helper scripts, migration, setup checks, and contract verification wrappers; Git-for-Windows Bash is the Windows platform contract |
228
228
  | `npm` | npm registry | registry readbacks, publish gates, and opt-in update checks; not repo-harness-owned global install repair |
229
229
  | `npx` / `skills_cli` | external Skills CLI | Waza and Mermaid skill bootstrap/update commands |
230
230
  | `rsync` | platform filesystem | Waza staging-to-Codex sync and installed-copy runtime mirroring |
@@ -236,6 +236,31 @@ CLI dependencies until a separate plan replaces that integration. Missing
236
236
  optional capabilities should degrade the named feature, not blur command
237
237
  ownership.
238
238
 
239
+ On Windows, `repo-harness install` and `repo-harness update` are the only
240
+ protected-helper tool discovery ceremonies. They resolve `git.exe` and
241
+ `taskkill.exe` from that invocation's `PATH`, require the latter to match
242
+ `SystemRoot\\System32\\taskkill.exe`, require Git, Bash, and `usr/bin` to
243
+ resolve under one non-symlink Git-for-Windows root, require the ceremony's
244
+ `TEMP` to be an absolute non-symlink directory, probe the executables, and
245
+ atomically persist protocol 1 under the OS account's
246
+ `~/.repo-harness/config.json#protectedHelperRuntime`. Existing sibling config
247
+ fields are preserved.
248
+
249
+ Normal `acceptance-receipt`, `merge-gate`, `contract-worktree`, and
250
+ `ship-worktrees` dispatch reads that exact contract. The protected child gets
251
+ the platform `PATH` delimiter, account home, pinned temp/SystemRoot values,
252
+ pinned Bun/Git/Bash, the Git-for-Windows POSIX directories, and the exact
253
+ `taskkill.exe` passed to both supervisor termination paths; caller binary overrides, `HOME`, shell
254
+ startup hooks, and general `PATH` entries are discarded. A missing, malformed,
255
+ relocated, symlinked, cross-root, or incomplete contract fails before helper
256
+ execution and instructs the operator to rerun install/update. There is no
257
+ runtime discovery fallback. The protected TypeScript entrypoints re-resolve the
258
+ same host contract themselves when invoked directly, so their Git and temp
259
+ authority does not depend on dispatcher-only environment variables. Optional
260
+ feature dependencies such as `jq` and `gh` remain separately operator-owned
261
+ and are not installed by this contract; the required merge-gate path does not
262
+ depend on `jq`.
263
+
239
264
  Installed-copy sync has two explicit modes. `AGENTIC_DEV_LINK_INSTALLED_COPIES=1`
240
265
  uses symlinks and does not require `rsync`; if symlink creation fails, the
241
266
  script reports unsupported link-mode and tells the caller to use copy-mode.
@@ -584,9 +609,9 @@ The exact target base commit enables the local gate in
584
609
  `.ai/harness/policy.json#merge_gate`; the candidate cannot disable that base
585
610
  requirement. Runtime setup installs no merge-gate skill, agent, or provider
586
611
  runtime. Caller `HOME`, helper-source, and runner environment overrides are ignored for
587
- the protected ship/gate helpers. The official runner also pins Bash, Git, Bun,
588
- and `gh` to installed host executables and replaces caller `PATH` with the
589
- minimal host runtime path. The host state directories, AcceptanceReceipt, and
612
+ the protected ship/gate helpers. The official runner pins Bash, Git, and Bun;
613
+ where a fixed trusted host `gh` is present it pins that executable too, and it
614
+ replaces caller `PATH` with the minimal host runtime path. The host state directories, AcceptanceReceipt, and
590
615
  seal must be owned by the OS account and not group/world writable. After
591
616
  `contract-worktree finish` creates the candidate commit, the installed helper
592
617
  binds the seal to repository root, target base ref/SHA, candidate head SHA,
@@ -642,11 +667,22 @@ mismatched, invalid, or unverified native observation blocks a role-routing
642
667
  claim and authorizes no alternate fleet runner. repo-harness must not scrape
643
668
  rollout JSONL or SQLite as a compatibility path.
644
669
 
645
- `developer_instructions` is the packaged `.md` body plus the canonical
646
- EXECUTION_BOUNDARY anti-extras clause, kept byte-identical to the
647
- `EXECUTION_BOUNDARY` constant in `scripts/contract-run.ts` so every generated
648
- Codex agent carries the same boundary as the Claude worker prompts, the MCP
649
- `codex-goal` path, and the Codex delegation advisor hook.
670
+ `developer_instructions` is the packaged `.md` role body only. Generated
671
+ personas carry no EXECUTION_BOUNDARY anti-extras clause, and neither does the
672
+ Codex delegation advisor hook: on the native-child path `SubagentStart.context`
673
+ is the single injection owner, so the clause appears exactly once in each
674
+ rendered task packet under the marker
675
+ `[repo-harness:execution-boundary/v1]`. The hook renders it only when both
676
+ halves of the scope decision are known — a resolved active contract and a child
677
+ whose selected profile declares `sandbox_mode = "workspace-write"`; a
678
+ `read-only` child gets the inverse note, and an unresolved contract or
679
+ unverified routing gets neither.
680
+
681
+ `sandbox_mode` is therefore required in every custom-agent TOML and validated
682
+ fail-closed. Writability is read from the selected profile, never inferred from
683
+ the agent name and never defaulted: a profile missing `sandbox_mode`, or
684
+ declaring anything other than `read-only` or `workspace-write`, routes the child
685
+ to native-role-routing `invalid` and receives no implementation boundary.
650
686
 
651
687
  ### `install_mode`: self-host vs. downstream
652
688
 
@@ -75,6 +75,14 @@ For architecture reviews, bug hunts, risky refactors, deployment issues, auth/pa
75
75
 
76
76
  Reports must be concise and grounded in files, commands, runtime behavior, observed code, or verified system state.
77
77
 
78
+ ## Artifact Hygiene
79
+
80
+ Write comments, commit messages, and PR text from the final diff only, as if discarded intermediate attempts never existed. Session history is not documentation material.
81
+
82
+ - Comments state only the non-obvious reason at the owning boundary; never restate the operation, preserve intermediate attempts, or list speculative future work.
83
+ - PR text states final behavior plus only the material rationale or trade-off a reviewer cannot recover from the diff; never mention never-merged states, reverted work, or why something is absent (no "(without X)" titles, no paragraphs justifying a removal the reviewer never saw).
84
+ - When the user rejects an addition, the correct artifact output is the version where that addition never existed — not an annotated explanation of its removal.
85
+
78
86
  ## Completion Summary Rule
79
87
 
80
88
  For non-trivial completed tasks, include a short `下一刀` section only when verified state shows a concrete next bottleneck, unresolved risk, failing check, deployment gap, review gap, or active-plan item that materially affects the user's stated goal.
@@ -231,6 +231,8 @@ evaluator never guesses semantic equivalence.
231
231
  worktree start records immutable provenance.
232
232
  - Execute the sprint in that linked worktree. The primary worktree remains a merge target and must stay clean before merge-back.
233
233
  - After implementation, run `repo-harness run verify-sprint --prepare-acceptance`, obtain exactly one semantic disposition from the contract-frozen reviewer (or an explicitly allowed typed user waiver), record the `AcceptanceReceipt`, then run `repo-harness run verify-sprint`. The final verification projects the receipt into the review file. The finish command consumes that same receipt, creates a provider-free exact local seal, applies the allowlisted lifecycle archive, and publishes one synthesized target commit whose tree is byte-identical to the verified lifecycle HEAD. The target base must remain frozen and its worktree must remain clean through publication.
234
+ - When architecture projection policy is `automatic`, `--prepare-acceptance` materializes it before computing the review subject. The generated `docs/architecture/.projection-manifest.json` is an exact workflow-owned publication output and does not need to be repeated in every contract `allowed_paths`; every other generated architecture/context path still needs explicit contract scope and otherwise fails closed. Provider unavailability or a non-publishable projection status aborts preparation. After a synthesized commit containing a manifest delta lands, closeout verifies the exact clean published tree and advances the architecture drift cursor to that publication SHA; recovery retries this acknowledgement before committing its journal. Post-publication Stop projection is recovery only, and closeout never restores or discards a dirty target manifest.
235
+ - On the primary checkout, a Stop drain whose only effect is a digest-only manifest restamp publishes itself as one single-path commit, so the steady state stays clean for those dirty gates instead of needing a manual batching commit. The classifier is the provider's own result — exactly one `update` entry for `docs/architecture/.projection-manifest.json` and no pending human action — so a semantic projection delta is never auto-committed. The git gate is fail-closed on top of that: primary worktree, attached local branch, clean index, the manifest as the only dirty tracked path, and no `commit.gpgsign`. The commit is synthesized with `commit-tree` plus an `update-ref` compare-and-swap, which runs no user hooks and reads no untracked or unstaged state, so staged content and working files are never swept in. Nothing is pushed and the architecture drift cursor is not touched; a publication that leaves the branch ahead of its remote prints one push advisory, and every skip or fault prints one advisory and still exits 0. `repo-harness architecture-projection publish-restamp --json` runs the same classifier, gate, and synthesis for manual recovery and exits non-zero unless it published.
234
236
 
235
237
  ## Publication Granularity
236
238
 
@@ -151,7 +151,10 @@
151
151
  ],
152
152
  "discoverability": "profile-facade",
153
153
  "component": "adaptive-workflow",
154
- "requires": [],
154
+ "requires": [
155
+ "obsidian-markdown",
156
+ "obsidian-cli"
157
+ ],
155
158
  "mutatesRepoByDefault": false,
156
159
  "summary": "Cross-project long-term memory over the user's Obsidian brain vault: recall relevant notes before a task and persist distilled conclusions after it. Repo artifacts stay the source of truth; sync direction is repo -> brain. Explicitly invoked by the model or operator, never from hooks. Requires the runtime-referenced official obsidian-markdown and obsidian-cli skills.",
157
160
  "retirementCandidate": null
@@ -336,6 +339,42 @@
336
339
  "mutatesRepoByDefault": false,
337
340
  "summary": "Explicit-opt-in reverse-engineering and security-task router pack. Fetched from zhaoxuya520/reverse-skill via bunx skills add after independent authorization review.",
338
341
  "retirementCandidate": null
342
+ },
343
+ {
344
+ "name": "obsidian-markdown",
345
+ "kind": "external",
346
+ "source": null,
347
+ "provider": "kepano/obsidian-skills@a1dc48e68138490d522c04cbf5822214c6eb1202",
348
+ "integrity": "sha256:ac9b702f9697f0bbf5f0fdc0c6896d94efef01438a59a4b508e5d7346da050e6",
349
+ "hosts": [
350
+ "claude",
351
+ "codex"
352
+ ],
353
+ "profiles": [],
354
+ "discoverability": "external-marketplace",
355
+ "component": "adaptive-workflow",
356
+ "requires": [],
357
+ "mutatesRepoByDefault": false,
358
+ "summary": "Explicit-opt-in official Obsidian Markdown authoring companion Skill. Pinned to kepano/obsidian-skills and verified before projection.",
359
+ "retirementCandidate": null
360
+ },
361
+ {
362
+ "name": "obsidian-cli",
363
+ "kind": "external",
364
+ "source": null,
365
+ "provider": "kepano/obsidian-skills@a1dc48e68138490d522c04cbf5822214c6eb1202",
366
+ "integrity": "sha256:58b3eaf9ccaadfcbe3b8d0eddb0d1fe872ef42c4cf289393a72d4e9a6d896f6f",
367
+ "hosts": [
368
+ "claude",
369
+ "codex"
370
+ ],
371
+ "profiles": [],
372
+ "discoverability": "external-marketplace",
373
+ "component": "adaptive-workflow",
374
+ "requires": [],
375
+ "mutatesRepoByDefault": false,
376
+ "summary": "Explicit-opt-in official Obsidian CLI companion Skill. Does not install or require the Obsidian executable or desktop App.",
377
+ "retirementCandidate": null
339
378
  }
340
379
  ],
341
380
  "expectedProjections": {
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.16.0",
3
- "templateVersion": "0.16.0",
2
+ "version": "0.16.2",
3
+ "templateVersion": "0.16.2",
4
4
  "skillName": "repo-harness",
5
5
  "contractId": "tasks-first-harness-v1",
6
6
  "compatibility": {
@@ -255,6 +255,14 @@
255
255
  {
256
256
  "version": "0.16.0",
257
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"
258
+ },
259
+ {
260
+ "version": "0.16.1",
261
+ "description": "Replaces the boolean `overwrite` flag on the seven MCP workflow-artifact write tools with an optional `expected_sha256` revision precondition (absent = create-only with WOULD_OVERWRITE, supplied = guarded overwrite with REVISION_CONFLICT and no current-hash echo), routes those writes through a guarded synchronous writer with lstat symlink and regular-file guards plus temp+fsync+rename+parent-fsync, returns sha256/previousSha256 on success, and rejects undeclared parameters server-side with UNKNOWN_PARAMETER while `overwrite` specifically returns RETIRED_PARAMETER naming `expected_sha256`"
262
+ },
263
+ {
264
+ "version": "0.16.2",
265
+ "description": "Fixes MCP runtime issues from #204, binds MCP HTTP sessions to the startup profile with fail-closed config-flip handling, publishes the architecture queue lock owner record atomically via staged hard-link creation, requires and fail-closed-validates sandbox_mode in Codex custom-agent TOMLs with EXECUTION_BOUNDARY persona de-duplication, and adds artifact-hygiene rules (final-diff-only comments and PR text) to the global working rules and generated agent contracts"
258
266
  }
259
267
  ],
260
268
  "generatedProjectStamp": {
@@ -13,6 +13,7 @@ import {
13
13
  writeFileSync,
14
14
  } from 'fs';
15
15
  import { userInfo } from 'os';
16
+ import { createRequire } from 'module';
16
17
  import { basename, dirname, isAbsolute, join, relative, resolve } from 'path';
17
18
  import { fileURLToPath, pathToFileURL } from 'url';
18
19
  import { spawnSync } from 'child_process';
@@ -87,10 +88,81 @@ type Options = {
87
88
  };
88
89
 
89
90
  const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
90
- const PACKAGE_ROOT = SCRIPT_DIR.endsWith('/assets/templates/helpers')
91
+ const PACKAGE_ROOT = basename(SCRIPT_DIR) === 'helpers'
92
+ && basename(dirname(SCRIPT_DIR)) === 'templates'
93
+ && basename(dirname(dirname(SCRIPT_DIR))) === 'assets'
91
94
  ? resolve(SCRIPT_DIR, '../../..')
92
95
  : resolve(SCRIPT_DIR, '..');
93
- const GIT_BIN = ['/usr/bin/git', '/bin/git'].find((path) => existsSync(path)) ?? 'git';
96
+ type ProtectedRuntime = {
97
+ platform: NodeJS.Platform;
98
+ accountHome: string;
99
+ accountUsername: string;
100
+ gitBin: string;
101
+ bashBin: string;
102
+ bunExecutable: string;
103
+ pathEntries: readonly string[];
104
+ pathDelimiter: ':' | ';';
105
+ tempDir: string;
106
+ systemRoot?: string;
107
+ };
108
+ type ProtectedPlatformModule = {
109
+ resolveProtectedHelperPlatform: () => ProtectedRuntime;
110
+ protectedHelperRuntimeEnv: (runtime: ProtectedRuntime) => NodeJS.ProcessEnv;
111
+ };
112
+ type ProtectedGitRuntime = {
113
+ readonly gitBin: string;
114
+ readonly env: NodeJS.ProcessEnv;
115
+ };
116
+ const requireFromHelper = createRequire(import.meta.url);
117
+ let protectedGitRuntimeCache: ProtectedGitRuntime | null = null;
118
+
119
+ function fixedPosixExecutable(label: string, candidates: readonly string[]): string {
120
+ for (const candidate of candidates) {
121
+ if (!isAbsolute(candidate) || !existsSync(candidate)) continue;
122
+ const source = lstatSync(candidate);
123
+ if (source.isSymbolicLink() || !source.isFile()) continue;
124
+ const actual = realpathSync(candidate);
125
+ const target = lstatSync(actual);
126
+ if (target.isSymbolicLink() || !target.isFile() || (target.mode & 0o111) === 0) continue;
127
+ return actual;
128
+ }
129
+ throw new Error(`required system executable is unavailable: ${label}`);
130
+ }
131
+
132
+ export function resolveProtectedGitRuntime(): ProtectedGitRuntime {
133
+ if (protectedGitRuntimeCache) return protectedGitRuntimeCache;
134
+ if (process.platform !== 'win32') {
135
+ const account = userInfo();
136
+ const gitBin = fixedPosixExecutable('git', ['/usr/bin/git', '/bin/git']);
137
+ const bashBin = fixedPosixExecutable('bash', ['/bin/bash']);
138
+ const protectedPath = `${dirname(process.execPath)}:/usr/bin:/bin:/usr/sbin:/sbin`;
139
+ protectedGitRuntimeCache = {
140
+ gitBin,
141
+ env: {
142
+ HOME: account.homedir,
143
+ USER: account.username,
144
+ LOGNAME: account.username,
145
+ PATH: protectedPath,
146
+ TMPDIR: '/tmp',
147
+ REPO_HARNESS_BASH_BIN: bashBin,
148
+ REPO_HARNESS_GIT_BIN: gitBin,
149
+ REPO_HARNESS_BUN_BIN: process.execPath,
150
+ REPO_HARNESS_PROTECTED_PATH: protectedPath,
151
+ REPO_HARNESS_PROTECTED_TMPDIR: '/tmp',
152
+ },
153
+ };
154
+ return protectedGitRuntimeCache;
155
+ }
156
+ const protectedPlatform = requireFromHelper(
157
+ join(PACKAGE_ROOT, 'src', 'cli', 'runtime', 'protected-helper-platform.ts'),
158
+ ) as ProtectedPlatformModule;
159
+ const runtime = protectedPlatform.resolveProtectedHelperPlatform();
160
+ protectedGitRuntimeCache = {
161
+ gitBin: runtime.gitBin,
162
+ env: protectedPlatform.protectedHelperRuntimeEnv(runtime),
163
+ };
164
+ return protectedGitRuntimeCache;
165
+ }
94
166
 
95
167
  function fail(message: string, code = 1): never {
96
168
  const error = new Error(message) as Error & { exitCode?: number };
@@ -123,7 +195,8 @@ function isRecord(value: unknown): value is Record<string, unknown> {
123
195
  }
124
196
 
125
197
  function gitText(root: string, args: string[]): string {
126
- const result = spawnSync(GIT_BIN, ['-C', root, ...args], { encoding: 'utf-8' });
198
+ const runtime = resolveProtectedGitRuntime();
199
+ const result = spawnSync(runtime.gitBin, ['-C', root, ...args], { encoding: 'utf-8', env: runtime.env });
127
200
  if (result.status !== 0) fail(`git ${args.join(' ')} failed: ${result.stderr.trim() || 'unknown error'}`);
128
201
  return result.stdout.trim();
129
202
  }
@@ -478,7 +551,8 @@ function resolveArchived(root: string, path: string, family: 'plans' | 'tasks',
478
551
  if (existsSync(resolve(root, path))) return path;
479
552
  const archiveRoot = join(root, family, 'archive');
480
553
  if (!existsSync(archiveRoot)) fail(`receipt authority file is missing: ${path}`);
481
- const tracked = spawnSync(GIT_BIN, ['-C', root, 'ls-files', `${family}/archive`], { encoding: 'utf-8' })
554
+ const runtime = resolveProtectedGitRuntime();
555
+ const tracked = spawnSync(runtime.gitBin, ['-C', root, 'ls-files', `${family}/archive`], { encoding: 'utf-8', env: runtime.env })
482
556
  .stdout.split(/\r?\n/).filter(Boolean);
483
557
  const matches = tracked.filter((candidate) => {
484
558
  const absolute = resolve(root, candidate);
@@ -3,6 +3,7 @@ import { createHash, randomUUID } from "crypto";
3
3
  import {
4
4
  closeSync,
5
5
  existsSync,
6
+ linkSync,
6
7
  lstatSync,
7
8
  mkdirSync,
8
9
  openSync,
@@ -520,18 +521,34 @@ function acquireQueueLock(requestsDir: string, ownerPid: number, ownerToken: str
520
521
  assertSafeWriteTarget(`${requestsDir}/.write-probe`);
521
522
  const lockFile = ".ai/harness/architecture/.architecture-queue.lock";
522
523
  assertSafeWriteTarget(lockFile);
524
+ const candidateToken = createHash("sha256").update(ownerToken).digest("hex").slice(0, 16);
525
+ const candidateFile = `${lockFile}.${ownerPid}.${candidateToken}.tmp`;
526
+ assertSafeWriteTarget(candidateFile);
523
527
  const deadline = Date.now() + 10_000;
524
528
  while (true) {
525
529
  try {
526
- const fd = openSync(lockFile, "wx", 0o600);
530
+ const fd = openSync(candidateFile, "wx", 0o600);
527
531
  try {
528
532
  writeAllSync(fd, JSON.stringify({ pid: ownerPid, token: ownerToken, created_at: new Date().toISOString() }));
529
533
  } finally {
530
534
  closeSync(fd);
531
535
  }
532
- return lockFile;
536
+ const holdBeforePublishMs = Number(process.env.REPO_HARNESS_ARCHITECTURE_HOLD_BEFORE_LOCK_PUBLISH_MS || "0");
537
+ if (Number.isFinite(holdBeforePublishMs) && holdBeforePublishMs > 0) {
538
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, holdBeforePublishMs);
539
+ }
540
+ try {
541
+ linkSync(candidateFile, lockFile);
542
+ return lockFile;
543
+ } catch (error: any) {
544
+ if (error?.code !== "EEXIST") throw error;
545
+ }
533
546
  } catch (error: any) {
534
- if (error?.code !== "EEXIST" || !existsSync(lockFile)) throw error;
547
+ if (error?.code !== "EEXIST") throw error;
548
+ } finally {
549
+ rmSync(candidateFile, { force: true });
550
+ }
551
+ if (existsSync(lockFile)) {
535
552
  try {
536
553
  const owner = JSON.parse(readFileSync(lockFile, "utf8"));
537
554
  if (!processIsAlive(Number(owner.pid))) {
@@ -545,9 +562,9 @@ function acquireQueueLock(requestsDir: string, ownerPid: number, ownerToken: str
545
562
  continue;
546
563
  }
547
564
  }
548
- if (Date.now() >= deadline) throw new Error(`architecture queue lock unavailable: ${lockFile}`);
549
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 25);
550
565
  }
566
+ if (Date.now() >= deadline) throw new Error(`architecture queue lock unavailable: ${lockFile}`);
567
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 25);
551
568
  }
552
569
  }
553
570