simt-dev 0.6.3 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/CHANGELOG.md +162 -841
  2. package/README.md +21 -135
  3. package/agents/simt-agent.md +84 -0
  4. package/bin/simt.mjs +19 -55
  5. package/docs/decisions/ADR-009-skill-layout.md +1 -1
  6. package/docs/decisions/ADR-014-workspace-is-configuration.md +1 -1
  7. package/docs/decisions/ADR-086-the-stable-prefix-comes-first-and-the-lock-records-both-digests.md +1 -1
  8. package/docs/decisions/ADR-099-the-release-verifies-served-bytes-and-the-formula-mirrors-them.md +1 -1
  9. package/docs/decisions/ADR-106-the-harness-hook-runs-through-a-repo-shim.md +46 -0
  10. package/docs/decisions/ADR-107-an-install-can-name-one-harness-and-the-skipped-ones-are-named.md +51 -0
  11. package/docs/decisions/ADR-108-an-adoption-builds-the-index-and-a-command-refreshes-it-on-read.md +59 -0
  12. package/docs/decisions/ADR-109-simt-dev-is-its-own-consumer-and-the-guards-that-kept-it-from-being-one-are-retired.md +47 -0
  13. package/docs/decisions/ADR-110-the-lock-file-follows-the-manifest-name-and-the-old-name-is-read-until-the-next-write.md +43 -0
  14. package/docs/decisions/ADR-111-the-tool-ships-one-agent-rendered-per-harness-and-installs-it-with-init-and-a-command.md +75 -0
  15. package/docs/decisions/ADR-112-the-registry-is-what-simt-dev-ships-and-a-repo-owns-its-own-skills.md +81 -0
  16. package/docs/decisions/ADR-113-a-pre-push-that-carries-only-documentation-skips-the-test-gate-and-says-so.md +87 -0
  17. package/docs/decisions/ADR-114-the-bench-pairs-at-the-task-level-a-missing-cost-is-not-zero-and-an-unasked-cross-group-compare-is-refused.md +74 -0
  18. package/docs/decisions/ADR-115-the-index-stamps-its-schema-version-migrates-older-databases-in-place-and-serves-newer-ones-from-a-sidecar.md +69 -0
  19. package/docs/decisions/ADR-116-rust-support-reaches-the-example-path-the-indent-and-the-bench-runner.md +100 -0
  20. package/docs/decisions/ADR-117-the-darwin-release-builds-on-supported-macos-15-runners-and-a-re-run-is-idempotent.md +81 -0
  21. package/docs/decisions/ADR-118-the-bench-corpus-is-keyed-on-history-is-append-only-and-is-portable-as-a-sealed-document.md +91 -0
  22. package/docs/decisions/ADR-119-the-environment-variable-points-into-a-workspace-the-repo-declared.md +90 -0
  23. package/docs/decisions/ADR-120-a-pre-push-whose-tree-is-already-proven-green-skips-the-test-gate-on-that-evidence.md +96 -0
  24. package/docs/decisions/ADR-122-the-shims-move-into-the-state-directory-and-the-legacy-directory-removes-itself.md +94 -0
  25. package/docs/decisions/ADR-123-a-surplus-positional-is-not-refused-because-arity-is-not-in-the-source.md +57 -0
  26. package/docs/decisions/ADR-124-the-manifest-has-a-schema-in-the-tool-and-its-unknown-keys-stay-the-repositorys.md +64 -0
  27. package/docs/decisions/ADR-125-a-shared-context-belongs-to-a-read-and-a-writer-reads-directly.md +65 -0
  28. package/package.json +13 -3
  29. package/rules/core.md +9 -2
  30. package/rules/mdc/slice-commit.mdc +57 -4
  31. package/rules/mdc/test-gate.mdc +2 -0
  32. package/rules/stacks/android.md +3 -3
  33. package/rules/stacks/connectiq.md +2 -2
  34. package/rules/stacks/dart.md +1 -1
  35. package/rules/stacks/deno.md +1 -1
  36. package/rules/stacks/dotnet.md +1 -1
  37. package/rules/stacks/elixir.md +1 -1
  38. package/rules/stacks/go.md +1 -1
  39. package/rules/stacks/jvm.md +3 -2
  40. package/rules/stacks/node.md +2 -2
  41. package/rules/stacks/python.md +7 -6
  42. package/rules/stacks/ruby.md +1 -1
  43. package/rules/stacks/rust.md +1 -1
  44. package/rules/stacks/swift.md +1 -1
  45. package/rules/stacks/typescript.md +2 -2
  46. package/rules/stacks/uv.md +3 -2
  47. package/skills/simt-commands/SKILL.md +70 -0
  48. package/src/advice/advice.mjs +7 -3
  49. package/src/agenthooks/decide.mjs +141 -9
  50. package/src/agenthooks/opencode.mjs +72 -0
  51. package/src/agenthooks/prompt.mjs +10 -3
  52. package/src/agenthooks/render.mjs +186 -19
  53. package/src/agenthooks/shim.mjs +55 -0
  54. package/src/agents/render.mjs +277 -0
  55. package/src/api.mjs +29 -0
  56. package/src/argv.mjs +37 -3
  57. package/src/bench/ablate.mjs +31 -14
  58. package/src/bench/adapters.json +16 -0
  59. package/src/bench/corpus.mjs +150 -0
  60. package/src/bench/grade.mjs +23 -49
  61. package/src/bench/mine.mjs +247 -36
  62. package/src/bench/probes.mjs +104 -68
  63. package/src/bench/process.mjs +128 -0
  64. package/src/bench/report.mjs +260 -84
  65. package/src/bench/run.mjs +251 -150
  66. package/src/bench/variants.mjs +112 -40
  67. package/src/brief/assemble.mjs +44 -3
  68. package/src/ci/workflow.mjs +46 -14
  69. package/src/cli.mjs +45 -0
  70. package/src/commands/agent.mjs +205 -0
  71. package/src/commands/agenthook.mjs +113 -20
  72. package/src/commands/bench.mjs +192 -18
  73. package/src/commands/brief.mjs +5 -4
  74. package/src/commands/ci.mjs +2 -1
  75. package/src/commands/compare.mjs +50 -49
  76. package/src/commands/completions.mjs +2 -6
  77. package/src/commands/decide.mjs +10 -9
  78. package/src/commands/distill.mjs +4 -3
  79. package/src/commands/doctor.mjs +11 -7
  80. package/src/commands/evidence.mjs +19 -12
  81. package/src/commands/explain.mjs +0 -1
  82. package/src/commands/gate.mjs +98 -28
  83. package/src/commands/graph.mjs +20 -8
  84. package/src/commands/harness.mjs +3 -2
  85. package/src/commands/help.mjs +160 -31
  86. package/src/commands/hooks.mjs +163 -50
  87. package/src/commands/ignore.mjs +2 -1
  88. package/src/commands/impact.mjs +8 -9
  89. package/src/commands/index.mjs +278 -180
  90. package/src/commands/init.mjs +171 -38
  91. package/src/commands/lease.mjs +206 -39
  92. package/src/commands/lessons.mjs +72 -15
  93. package/src/commands/local.mjs +3 -3
  94. package/src/commands/map.mjs +47 -27
  95. package/src/commands/mcp.mjs +0 -1
  96. package/src/commands/pack.mjs +9 -6
  97. package/src/commands/plan.mjs +6 -5
  98. package/src/commands/plugin.mjs +3 -3
  99. package/src/commands/prbody.mjs +3 -3
  100. package/src/commands/repoindex.mjs +5 -3
  101. package/src/commands/review.mjs +2 -2
  102. package/src/commands/rules.mjs +124 -33
  103. package/src/commands/shared.mjs +2 -3
  104. package/src/commands/skills.mjs +82 -45
  105. package/src/commands/skillscompile.mjs +12 -12
  106. package/src/commands/skillsinstall.mjs +14 -2
  107. package/src/commands/slice.mjs +396 -26
  108. package/src/commands/spec.mjs +151 -0
  109. package/src/commands/status.mjs +4 -7
  110. package/src/commands/sync.mjs +50 -33
  111. package/src/commands/tests.mjs +11 -11
  112. package/src/commands/tokens.mjs +2 -2
  113. package/src/commands/undo.mjs +29 -31
  114. package/src/commands/upgrade.mjs +40 -4
  115. package/src/commands/why.mjs +19 -12
  116. package/src/compare/hooksstate.mjs +23 -1
  117. package/src/compare/learn.mjs +82 -57
  118. package/src/compare/parallel.mjs +50 -0
  119. package/src/compare/row.mjs +26 -3
  120. package/src/completions.mjs +5 -0
  121. package/src/context.mjs +64 -0
  122. package/src/decisions/dir.mjs +84 -0
  123. package/src/decisions/index-doc.mjs +46 -0
  124. package/src/decisions/index.mjs +109 -11
  125. package/src/diff.mjs +1 -1
  126. package/src/distill/distill.mjs +17 -2
  127. package/src/distill/engine.mjs +5 -1
  128. package/src/ecosystem/node-runner.mjs +144 -0
  129. package/src/explain.mjs +18 -6
  130. package/src/graph/load.mjs +42 -20
  131. package/src/hooks/capability.mjs +17 -4
  132. package/src/hooks/dispatcher.mjs +513 -36
  133. package/src/hooks/gates.mjs +0 -43
  134. package/src/hooks/resolve.mjs +11 -10
  135. package/src/hooks/shim.mjs +17 -9
  136. package/src/identity.mjs +96 -15
  137. package/src/index/extract.mjs +192 -11
  138. package/src/index/persist.mjs +307 -47
  139. package/src/index/store.mjs +263 -60
  140. package/src/index/tests.mjs +6 -35
  141. package/src/journal.mjs +372 -84
  142. package/src/kernel/card.mjs +37 -12
  143. package/src/kernel/checks.mjs +44 -9
  144. package/src/kernel/variants.mjs +27 -16
  145. package/src/lease.mjs +97 -15
  146. package/src/ledger/index.mjs +120 -25
  147. package/src/local/client.mjs +4 -6
  148. package/src/locate.mjs +33 -9
  149. package/src/manifest/schema.mjs +213 -0
  150. package/src/mcp/resources.mjs +12 -13
  151. package/src/mcp/server.mjs +151 -38
  152. package/src/mcp/tools.mjs +90 -16
  153. package/src/measure/session.mjs +3 -2
  154. package/src/memory/decide.mjs +98 -43
  155. package/src/memory/lessons.mjs +168 -33
  156. package/src/name.mjs +9 -0
  157. package/src/node-version.mjs +37 -0
  158. package/src/output/index.mjs +111 -3
  159. package/src/packs/manage.mjs +17 -3
  160. package/src/packs.mjs +20 -2
  161. package/src/plan/index.mjs +31 -8
  162. package/src/plan/template.mjs +27 -5
  163. package/src/plugins.mjs +6 -2
  164. package/src/prbody.mjs +7 -5
  165. package/src/projection/baselines.mjs +1 -1
  166. package/src/projection/disclosure.mjs +2 -2
  167. package/src/projection/loaders.mjs +41 -1
  168. package/src/projection/lock.mjs +31 -14
  169. package/src/projection/manifest.mjs +89 -53
  170. package/src/projection/markers.mjs +43 -3
  171. package/src/projection/mdc.mjs +34 -7
  172. package/src/projection/project.mjs +162 -18
  173. package/src/projection/rules.mjs +58 -6
  174. package/src/projection/surfaces.mjs +9 -1
  175. package/src/repo-root.mjs +88 -0
  176. package/src/resolve/body.mjs +4 -0
  177. package/src/resolve/fingerprint.mjs +24 -15
  178. package/src/resolve/local.mjs +58 -0
  179. package/src/review/critic.mjs +6 -3
  180. package/src/secrets.mjs +165 -22
  181. package/src/state.mjs +76 -0
  182. package/src/status.mjs +9 -4
  183. package/src/toolwords.mjs +8 -0
  184. package/src/tsconfig.mjs +39 -99
  185. package/src/workspace.mjs +55 -10
  186. package/templates/plan/tracker.json +1 -1
  187. package/docs/decisions/README.md +0 -591
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # simt-dev
2
2
 
3
- ![simt-dev, the intelligence amplifier for coding agents, and its four claims. One: say less, always — a kernel under 2 KB whose bytes stay stable so the prompt cache survives. Two: answers over exploration — a local code graph and a short task brief. Three: enforce, don't instruct — dual gates, before a tool call and at git time. Four: close the loop — benches and memory. Beneath them, the harnesses it works across and its three channels.](https://raw.githubusercontent.com/QuazarMedia/simt-dev/main/res/59e21e6d-6bf2-4d7d-b6ea-c7349a697d11.jpg)
3
+ ![simt-dev, the intelligence amplifier for coding agents, and its four claims. One: say less, always — a kernel under 2 KB whose bytes stay stable so the prompt cache survives. Two: answers over exploration — a local code graph and a short task brief. Three: enforce, don't instruct — dual gates, before a tool call and at git time. Four: close the loop — benches and memory. Beneath them, the harnesses it works across and its three channels.](https://raw.githubusercontent.com/QuazarMedia/simt-dev/main/res/hero.jpg)
4
+
5
+ [![simt-dev own gate](https://github.com/QuazarMedia/simt-dev/actions/workflows/simt-dev-check.yml/badge.svg)](https://github.com/QuazarMedia/simt-dev/actions/workflows/simt-dev-check.yml)
4
6
 
5
7
  `simt` adopts a repository for the agents that work in it, and builds an intelligence
6
8
  amplifier around them: a brief that answers before the agent explores, gates that
@@ -72,13 +74,20 @@ beside its `.sha256`. Pin the release you download,
72
74
  and run this from the repository's top level:
73
75
 
74
76
  ```sh
75
- mkdir -p .simt/bin && os=$(uname -s | tr A-Z a-z) && arch=$(uname -m | sed "s/x86_64/x64/") && curl -fsSL "https://github.com/QuazarMedia/simt-dev/releases/download/v<version>/simt-dev-<version>-$os-$arch" -o .simt/bin/simt && chmod +x .simt/bin/simt
77
+ version=<version>; os=$(uname -s | tr A-Z a-z); arch=$(uname -m | sed "s/x86_64/x64/")
78
+ base="https://github.com/QuazarMedia/simt-dev/releases/download/v$version"
79
+ asset="simt-dev-$version-$os-$arch"; tmp=$(mktemp -d)
80
+ curl -fsSL "$base/$asset" -o "$tmp/$asset"
81
+ curl -fsSL "$base/$asset.sha256" -o "$tmp/$asset.sha256"
82
+ (cd "$tmp" && shasum -a 256 -c "$asset.sha256")
83
+ mkdir -p .simt/bin && mv "$tmp/$asset" .simt/bin/simt && chmod +x .simt/bin/simt
76
84
  ```
77
85
 
78
86
  The locator checks `.simt/bin/simt` before `PATH`, so the repository's own copy is the
79
87
  one its hooks and its CI run — this is the same command the hook shim prints as its
80
- remedy. The generated CI workflow downloads the same asset and verifies it against the
81
- published `.sha256` before running anything.
88
+ remedy. Both the snippet above and the generated CI workflow verify the asset against the
89
+ published `.sha256` before it runs: a digest that does not match stops the copy, so a
90
+ truncated or substituted download never becomes the command.
82
91
 
83
92
  ## What `simt` does
84
93
 
@@ -152,7 +161,7 @@ simt bench run --yes # evaluate arms (bare, current, kernel, brie
152
161
  simt bench report [--compare a b] # resolved rate, quality, cost, CPI, bootstrap CIs, McNemar/Wilcoxon
153
162
  simt bench ablate --yes # leave-one-out rule ablation ranked by value per KB
154
163
  simt bench probes --yes # 12 deterministic rule-compliance probes
155
- simt bench variants --yes # evaluate simt-variants slots and lock winners in simt-dev.lock.json
164
+ simt bench variants --yes # evaluate simt-variants slots and lock winners in simt.lock.json
156
165
  simt review [--local] # an advisory ADR-008 verdict skeleton over the staged diff
157
166
  simt distill <skill|doc> # a budgeted proposal summary with line citations, for a person to merge
158
167
  simt pack new <name> --source <spec> # scaffold a versioned pack: pack.json, bench.json, one rule
@@ -185,134 +194,11 @@ line warns past 400 lines and fails past 1000. `simt evidence check` warns when
185
194
  message claims a passing run this tree does not have, and the commit fails when
186
195
  `gates.evidence` is `block`. Every finding `check` can emit is explained by `simt explain <CODE>` (DRIFT, UNMANAGED, PACK-DIGEST-MISMATCH, ...).
187
196
 
188
- ## Agent playbook: how and when to use each module
189
-
190
- An agent working in an adopted repository should use `simt` as its primary orientation,
191
- retrieval, validation and memory layer rather than scanning the tree by hand. Every
192
- read-only command supports `--json` (and `--max-bytes <n>`) or can be called over stdio
193
- through `simt mcp`.
194
-
195
- ### Decision tree: which command to run when
196
-
197
- | Situation | First command | If you need more |
198
- | --- | --- | --- |
199
- | New task, no context yet | `simt brief "<task>"` | `simt map --task "<task>"` for broader file ranking |
200
- | About to edit a file | `simt why <file>` | `simt impact <file>` for blast radius |
201
- | Need to know what tests to run | `simt tests <file>` | `simt gate --changed` to run them |
202
- | Rule violation or error | `simt lessons list` | `simt rules why <rule-id>` for the decision |
203
- | Working from a plan | `simt plan next` | `simt plan done <id> <sha> --yes` when finished |
204
- | Before committing | `simt check` | `simt evidence` to verify test claims |
205
- | Opening a pull request | `simt pr-body` | `--base <ref>` to diff against another fork point |
206
- | Repository adoption | `simt init --yes` | `simt doctor` to verify stack detection |
207
- | Multi-repo workspace | `simt compare` | `simt shared plan` to find deduplication opportunities |
208
- | Local model available | `simt local doctor` | `simt index --embed` to build vector embeddings |
209
-
210
- ### 1. Start of task — orient in one call instead of broad exploration
211
-
212
- 1. **Assemble the task packet first.** Run `simt brief "<task>"` (or call MCP `brief`, or
213
- read the packet injected automatically when `agent-hooks install --yes` wired
214
- `prompt-submit`). Within `--budget 2048` bytes (pass `--budget 0` for unlimited or
215
- `--explain` to see why items were kept or cut), the packet gives:
216
- - `TASK`: the classified task kind (`bugfix`, `feature`, `refactor`, `test`, `docs`,
217
- `config`) and the evidence behind it.
218
- - `COMMANDS`: the exact `build`, `test`, `lint`, `format`, `typecheck`, and focused
219
- test templates for this repository.
220
- - `LIKELY FILES`: top files ranked by reciprocal-rank fusion (`RRF_K = 40`) across
221
- SQLite FTS5 `bm25()`, PageRank graph proximity, and resolver signals.
222
- - `TESTS`: the test files mapped to those likely files.
223
- - `DECISIONS`, `SKILLS`, `LESSONS`, `CAUTIONS`, and `FEDERATION`: governing ADRs,
224
- matched skills, promoted lessons for those paths, active worktree/hook cautions, and
225
- any structural answer from a declared external code-graph server.
226
- 2. **Pull the next tracker slice when working from a plan.** Instead of reading a multi-thousand-line
227
- plan in `docs/plans/` or `docs/reviews/`, run `simt plan next` (or MCP `plan_next`) to
228
- load only the next queued slice (~1 KB) whose dependencies are already `Complete` or
229
- `Accepted`.
230
-
231
- **When to use `--json` format.** When piping output to other tools or when the agent needs
232
- structured data, add `--json` to any read-only command. For example, `simt brief "<task>" --json`
233
- returns a JSON object with `task`, `commands`, `files`, `tests`, `decisions`, `skills`,
234
- `lessons`, `cautions`, and `federation` fields that can be programmatically consumed.
235
-
236
- ### 2. Before editing — query the graph, blast radius, and governance
237
-
238
- 1. **Rank files or symbols at the right granularity.** When `brief`'s file list is too
239
- narrow or the task evolves, run `simt map --task "<task>" --level outline` for paths,
240
- `--level names` for exported symbols, or `--level signatures` for declaration lines.
241
- Pass `--embed` when `local.embed` is configured in `simt.json` and clears the +10-point
242
- recall@10 bar.
243
- 2. **Check blast radius before changing a shared file or export.** Run
244
- `simt impact <file|symbol>` to see every direct and transitive importer, the tests
245
- covering them, the governing rules and ADRs, and any sibling repository in the
246
- workspace that imports that symbol.
247
- 3. **Read the governance on a path before changing its behaviour.** Run `simt why <path>`
248
- to list every ADR whose `simt-affects` matches the file, every scoped rule, skill,
249
- gate, and promoted lesson. Run `simt why` with no path to audit the repository for
250
- `UNRESOLVED-AFFECTS` tokens.
251
- 4. **Resolve deferred rules and citations on demand.** When `simt.json` sets
252
- `"mode": "kernel"`, only `hard` and `command` rules are loaded at session start;
253
- `convention` and `style` rules are listed by ID at the foot of the projection. Fetch a
254
- deferred rule with `simt rules show <id>`, and read any cited `ADR-NNN` with
255
- `simt rules why ADR-NNN` (or MCP `rules_why`) to see its rulings and whether any ruling
256
- was superseded or narrowed.
257
- 5. **Load skills progressively (Tier 0 → Tier 1 → Tier 2).** Never read every skill file
258
- upfront:
259
- - Tier 0: `simt skills index` (or MCP `skills_index`) lists one line per skill.
260
- - Tier 1: `simt skills brief --task "<task>"` (or MCP `skills_brief`) ranks compatible
261
- skills within budget (`--plan` emits a fetch plan without bodies).
262
- - Tier 2: `simt skills show <name> --max-bytes 8192` (or MCP `skills_show`) loads only
263
- the chosen skill's body.
264
-
265
- **Optimal retrieval strategy.** For best performance, use this sequence:
266
- 1. `simt brief "<task>"` — gets the most relevant files and tests in one call
267
- 2. If more files are needed, `simt map --task "<task>" --level outline` — broader ranking
268
- 3. If you need to understand a specific file's impact, `simt impact <file>` — blast radius
269
- 4. If you need to understand governance, `simt why <file>` — ADRs and rules
270
-
271
- ### 3. During implementation — validate incrementally under dual gates
272
-
273
- 1. **Keep the local index current.** After adding, renaming, or changing exports/imports,
274
- run `simt index`. It hashes tracked blobs via `git ls-files --stage` and re-extracts
275
- only changed files in under 300 ms.
276
- 2. **Run only the tests your change reaches.** Use `simt tests <path>` to inspect which
277
- tests cover a file (via import edges, naming conventions, or coverage records; add
278
- `--cochange` to include historical co-change pairs). Run `simt gate --changed` (or
279
- `simt gate <path...>`) to execute only the tests reachable from the diff, with gate
280
- output compacted so every failure line survives while passing noise is trimmed.
281
- 3. **Respect agent-time hooks and learn from failures.** With `simt agent-hooks install --yes`,
282
- `pre-tool-use` blocks unapproved `git push`, history rewrites (`--no-verify`,
283
- `--amend`, `reset --hard`, `rebase`), and direct edits to generated regions before the
284
- tool executes. When a test or gate fails, `post-tool-use` hashes the normalised first
285
- error line against `docs/lessons/*.md` and injects the matching lesson into context.
286
-
287
- **Incremental validation workflow.** After each meaningful code change:
288
- 1. Run `simt tests <changed-file>` to see which tests cover your changes
289
- 2. Run `simt gate --changed` to execute only the affected tests
290
- 3. If a test fails, check `simt lessons list` for known issues and their remedies
291
- 4. If the failure is new, fix it and consider promoting the lesson with `simt lessons review <id> --yes`
292
-
293
- ### 4. Before committing and closing a slice — verify drift, evidence, and memory
294
-
295
- 1. **Run the repository gate.** Run `simt check` (or MCP `check`). Fix any reported
296
- `DRIFT` with `simt sync --yes`, and resolve any rule checker or manifest findings.
297
- 2. **Verify execution evidence matches the current tree.** Run `simt evidence` to confirm
298
- that the tests and gates you plan to cite were recorded against the current
299
- `git write-tree` digest in `.simt/ledger.jsonl`. Any file edit invalidates earlier
300
- evidence.
301
- 3. **Record decisions, lessons, and tracker state:**
302
- - If the change alters what the repository or tool believes, scaffold an ADR with
303
- `simt decide "<title>" [--supersedes ADR-NNN[:<ruling>]] --yes`.
304
- - If a failing gate or test was fixed during the session, inspect captured candidates
305
- with `simt lessons list` and promote reusable ones with
306
- `simt lessons review <id> --yes`.
307
- - After committing locally (never push without explicit approval per `ADR-001`), close
308
- the tracker slice with `simt plan done <id> <sha> --test "<cmd>" --yes`.
309
-
310
- **Pre-commit checklist.** Before committing, run this sequence:
311
- 1. `simt check` — verify no drift and all rules pass
312
- 2. `simt evidence` — confirm test runs are recorded against current tree
313
- 3. `simt lessons list` — check for any unreviewed lesson candidates
314
- 4. `git commit` — commit locally (never push without explicit approval)
315
- 5. `simt plan done <id> <sha> --yes` — close the tracker slice if working from a plan
197
+ ## Agent playbook
198
+
199
+ The full agent playbook — the decision tree for which command to run when, and the
200
+ workflow for orienting, editing, implementing and closing a slice — lives in
201
+ [PLAYBOOK.md](PLAYBOOK.md).
316
202
 
317
203
  ## Optimal setup for every project, repository, and workspace shape
318
204
 
@@ -369,10 +255,10 @@ history. All remain off until named and propose rather than write projected text
369
255
  | --- | --- |
370
256
  | `AGENTS.md` (and `<package>/AGENTS.md` in monorepos) | the projection, between `<!-- simt:begin -->` and `<!-- simt:end -->`. The old `simt-dev:` markers are still read, and a region migrates on its next write |
371
257
  | `simt.json` | the manifest: `gates`, `substitutions`, `budget`, `mode`, `shared`, `surfaces`, `plans`, `packs`, `federation`, `local` |
372
- | `simt-dev.lock.json` | the digest of the inputs, the digest of the projection, and locked `variants` winners from `simt bench variants` |
258
+ | `simt.lock.json` | the digest of the inputs, the digest of the projection, and locked `variants` winners from `simt bench variants`. The old `simt-dev.lock.json` is still read, and a lock migrates on its next write |
373
259
  | `.cursor/rules/*.mdc`, `.claude/rules/*.md`, `.agents/rules/*.md`, `.github/instructions/*.instructions.md` | one file per rule, and only for a harness that reads that directory |
374
260
  | `.editorconfig`, `.gitattributes` | baseline regions, placed first so a later setting still wins |
375
- | `.simt-hooks/` and `core.hooksPath` | the shared dispatcher. It fails closed |
261
+ | `.simt/hooks/` and `core.hooksPath` | the shared dispatcher. It fails closed |
376
262
  | `docs/decisions/ADR-NNN-<slug>.md` | numbered decision records scaffolded by `simt decide --yes` with `simt-affects` and `simt-supersedes` frontmatter |
377
263
  | `docs/lessons/NNNN-<slug>.md` | reviewed lessons promoted by `simt lessons review <id> --yes` with `simt-trigger`, `simt-evidence`, and `simt-expires` frontmatter |
378
264
 
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: Simt-Agent
3
+ description: Operates a repository with simt-dev: creates plan and review docs from the template, plans the next slice from the tracker, builds it, tests it, and commits it with evidence.
4
+ ---
5
+
6
+ You are the simt-dev operator for this repository. You do three jobs in one:
7
+ you **create the plan or review doc** when starting new work, you **plan** the
8
+ next piece of work from the tracker, and you **build** it. You act through the
9
+ `simt` commands the repository already runs, and you never claim a step you
10
+ did not take.
11
+
12
+ ## Orient before you act
13
+
14
+ - On a new task, run `simt brief "<task>"` before exploring. The packet tells
15
+ you how to run the tests, which files the task touches, and what governs them
16
+ — so you stop re-discovering what the repository already knows.
17
+ - Before editing a file, run `simt why <file>`. It lists the decisions, rules,
18
+ skills, gates and lessons that govern that file. Edit with those in mind.
19
+
20
+ ## Plan the next slice
21
+
22
+ - Read the tracker with `simt plan status` and `simt plan next`. `next` names
23
+ the smallest slice that is independently valuable, in dependency order.
24
+ - Resolve the open material decisions for that slice before building: ask 1–5
25
+ questions, recommended option first, and only where the authority documents
26
+ leave a real choice. Apply documented defaults without asking — operational
27
+ and procedural choices are not questions.
28
+ - State the slice you will take, the owning repository, the tracker task id,
29
+ and the acceptance checks, before you start.
30
+
31
+ ## Create the plan or review doc
32
+
33
+ When starting a new feature or a review, the deliverable is a file, not a
34
+ conversation. Write it before you build:
35
+
36
+ - **Plan:** `docs/plans/NNNN-slug.md` — the next number after the highest one
37
+ already in that directory. Open with `# Plan NNNN — Title`, a `Status:` line
38
+ (`**queued**` · created date), scope, and a tracker table with one row per
39
+ slice carrying an id, a state, and an evidence column. Each slice gets its
40
+ own section below the table.
41
+ - **Review:** `docs/reviews/NNNN-slug.md` — same numbering rule. Open with
42
+ `# Review NNNN — Title`, a `Status:` line, scope and method, severity
43
+ levels, and a tracker table or a pointer to the plan that owns the slices.
44
+ - Do not display the plan in the conversation and stop. The file is the
45
+ deliverable; the conversation is the working session.
46
+ - After the doc exists, track it with `simt plan status` and drive its rows
47
+ with `simt slice start` / `simt slice finish` / `simt plan done`.
48
+
49
+ ## Build one slice
50
+
51
+ - Start it with `simt slice start <id>`. This isolates the tracker row in its
52
+ own worktree with a task brief. Work only in that worktree.
53
+ - Make the smallest change that is independently valuable on its own. Do not
54
+ refactor outside the slice's blast radius.
55
+ - Run the focused test the change needs, through the repository's own runner,
56
+ naming the exact command and the exact test file. Every test must pass; a
57
+ partial pass is a blocker, not a result to quote.
58
+ - Stage only the files the slice touched. Leave unrelated work alone and say so.
59
+ Read the staged diff — not the working tree — before you commit.
60
+ - Finish it with `simt slice finish <id>`. This runs the declared gates, commits
61
+ with a Conventional Commits subject drawn from the row, and records the SHA.
62
+ - Record the slice complete with `simt plan done <id> <sha> --test "<command>"`,
63
+ carrying the evidence for the test you ran.
64
+
65
+ ## Dry run
66
+
67
+ Most simt-dev commands that write to the repository default to **dry-run**:
68
+ they print what they would change and exit without writing. Add `--yes` to
69
+ apply. Read the dry-run output first — it is the plan — then re-run with
70
+ `--yes`. A dry-run that shows an unexpected file is a reason to stop, not to
71
+ add `--yes` and hope.
72
+
73
+ For the full command reference — which commands are mutating vs read-only, and
74
+ the scenario-to-command mapping — read the `simt-commands` skill.
75
+
76
+ ## Boundaries you do not cross
77
+
78
+ - Never claim a test you did not run, a check you did not execute, or a commit
79
+ you did not make.
80
+ - Commit locally and report the SHA. Pushing is a separate decision that needs
81
+ its own approval; a finished slice is not a reason to push.
82
+ - Never use `--no-verify`, and never amend, rebase, reset or rewrite history
83
+ unless explicitly asked.
84
+ - A gate that cannot run blocks the commit; do not skip it to get a green line.
package/bin/simt.mjs CHANGED
@@ -1,60 +1,24 @@
1
1
  #!/usr/bin/env node
2
- // simt-dev - developer and agent tooling for the SIMT ecosystem.
2
+ // The entry point, and the one place the runtime floor is enforced.
3
3
  //
4
- // POSIX only (ADR-012). package.json declares os: [darwin, linux], so npm refuses
5
- // the install elsewhere rather than letting a hook fail obscurely.
6
-
7
- import { parse, rawJsonFlag } from '../src/argv.mjs';
8
- import { EXIT, fail, jsonFailMode, jsonIndentDefault } from '../src/output/index.mjs';
9
-
10
- try {
11
- const argv = process.argv.slice(2);
12
- const parsed = parse(argv);
13
- if (!parsed.ok) {
14
- // The flags do not exist yet, so the JSON mode is read off the raw words:
15
- // a parse failure under `--json` is a JSON document on stdout, not text on
16
- // stderr with an empty stdout (Q11, ADR-070 ruling 4).
17
- jsonFailMode(rawJsonFlag(argv));
18
- process.exit(fail(parsed.error.message, parsed.error.code));
19
- }
20
- const { flags, positional } = parsed.value;
21
-
22
- // Set before anything can fail: `no command given` under `--json` is a JSON
23
- // document too, and a failure that prints as text with an empty stdout breaks
24
- // the same ruling the parse failure above honours (Q11, ADR-070 ruling 4).
25
- jsonIndentDefault(flags.pretty === true);
26
- jsonFailMode(flags.json === true);
27
-
28
- // No arguments at all is a usage error, not a silent help dump: an agent that
29
- // ran the wrong thing should be told so rather than handed 40 lines of prose.
30
- if (positional.length === 0 && !flags.help && !flags.version) {
31
- process.exit(fail('no command given', EXIT.USAGE));
32
- }
4
+ // `package.json` declares `engines.node >= 22.20.0`, and npm only warns: an older
5
+ // runtime used to reach the CLI and fail somewhere inside the module graph — a syntax
6
+ // error or a missing API — instead of the one sentence that says what to install
7
+ // (review 0003 Q54). Nothing but this tiny module is imported before the check, so the
8
+ // message is what a reader gets; the CLI is imported only once the floor holds.
9
+ //
10
+ // 5 is EXIT.UNSUPPORTED. `output/index.mjs` is the CLI graph this file exists to avoid
11
+ // loading before the check, so the literal is repeated here and asserted by
12
+ // `test/node-version.test.mjs`.
33
13
 
34
- // The one command that runs on somebody else's hot path, and therefore the one that
35
- // does not load the registry. `agent-hook` is called before every tool call an agent
36
- // makes, so its latency is a product requirement rather than a nicety (plan 0003
37
- // R15), and the registry's imports - detection, projection, the bench corpus - cost
38
- // tens of milliseconds before the command itself starts. Measured on the machine
39
- // this was written on: 127.7 ms through the registry against 91.5 ms with only this
40
- // module's imports, where the bare runtime is 86.9 ms of it.
41
- //
42
- // Only the exact spelling the renderers write takes this path. Anything else -
43
- // including `agent-hook --help` - loads the registry, so help stays the one list of
44
- // every command and this shortcut cannot become a second, thinner command surface.
45
- if (positional[0] === 'agent-hook' && !flags.help && !flags.version) {
46
- const { agentHookCommand } = await import('../src/commands/agenthook.mjs');
47
- process.exit((await agentHookCommand(positional.slice(1), flags)) ?? EXIT.OK);
48
- }
14
+ import { MIN_NODE, satisfiesMinimum } from '../src/node-version.mjs';
49
15
 
50
- const { dispatch } = await import('../src/commands/index.mjs');
51
- const code = (await dispatch(argv)) ?? EXIT.OK;
52
- // Assigned, not forced: a large document on stdout (a `--json --diff` over a
53
- // skill-sized body exceeds the 64 KiB pipe buffer) is still draining when the
54
- // command resolves, and `process.exit()` cuts it — exit 0 with half a JSON
55
- // document on stdout. Letting the loop empty first makes the exit honest
56
- // (plan 0003 R50; the S10 contract asserts the document parses).
57
- process.exitCode = code;
58
- } catch (error) {
59
- process.exit(fail(error?.message ?? String(error), EXIT.FAIL));
16
+ if (!satisfiesMinimum(process.versions.node)) {
17
+ process.stderr.write(
18
+ `ERROR 5 simt-dev needs Node >= ${MIN_NODE}; this is ${process.versions.node}\n` +
19
+ `REMEDY install Node ${MIN_NODE} or newer, then rerun: simt --version\n`,
20
+ );
21
+ process.exit(5);
60
22
  }
23
+
24
+ await import('../src/cli.mjs');
@@ -1,6 +1,6 @@
1
1
  # ADR-009 — Skills are `<name>/SKILL.md` with mandatory frontmatter
2
2
 
3
- Status: **accepted** · 2026-10-05 · affects all repos
3
+ Status: **accepted** · 2026-10-05 · affects all repos · ruling 4 superseded by ADR-112
4
4
 
5
5
  ## Context
6
6
 
@@ -1,6 +1,6 @@
1
1
  # ADR-014 — The workspace is configuration, and a single repo is a first-class case
2
2
 
3
- Status: **accepted** · 2026-10-05
3
+ Status: **accepted** · 2026-10-05 · ruling 1 superseded by [ADR-119](ADR-119-the-environment-variable-points-into-a-workspace-the-repo-declared.md)
4
4
  Affects: `simt-dev` CLI (workspace resolution, `compare`, `skills`, registry validation, packaging)
5
5
 
6
6
  ## Context
@@ -1,6 +1,6 @@
1
1
  # ADR-086 — The stable prefix comes first, and the lock records both digests
2
2
 
3
- Status: **accepted** · 2026-10-18 · filed as R13 (plan 0003)
3
+ Status: **accepted** · 2026-10-18 · filed as R13 (plan 0003) · ruling 3's file name is superseded by [ADR-110](ADR-110-the-lock-file-follows-the-manifest-name-and-the-old-name-is-read-until-the-next-write.md)
4
4
 
5
5
  **Affects:** `src/projection/rules.mjs`, `src/projection/lock.mjs`, `src/commands/sync.mjs`,
6
6
  `src/argv.mjs`, `test/lock.test.mjs`, `test/card.test.mjs`
@@ -5,7 +5,7 @@ simt-supersedes: [{ adr: "ADR-098", ruling: 3, kind: "narrowed" }]
5
5
 
6
6
  # ADR-099 — the release verifies served bytes, and the formula mirrors them
7
7
 
8
- Status: **accepted** · 2026-10-27 · narrows ADR-098 ruling 3
8
+ Status: **accepted** · 2026-10-27 · narrows ADR-098 ruling 3 · ruling 1 superseded by [ADR-117](ADR-117-the-darwin-release-builds-on-supported-macos-15-runners-and-a-re-run-is-idempotent.md)
9
9
 
10
10
  Affects: `.github/workflows/publish.yml`, `scripts/build-sea.mjs`,
11
11
  `scripts/verify-release-asset.mjs`, `Formula/simt-dev.rb`
@@ -0,0 +1,46 @@
1
+ ---
2
+ simt-affects: ["src/agenthooks/shim.mjs", "src/agenthooks/render.mjs", "src/commands/agenthook.mjs"]
3
+ simt-supersedes: []
4
+ ---
5
+
6
+ # ADR-106 — the harness hook runs through a repo shim, and `failClosed` only with it
7
+
8
+ Status: **accepted** · 2026-10-29
9
+
10
+ ## Context
11
+
12
+ Review 0003 (Q21) verified by code-read that every harness config named the
13
+ bare `simt` binary. A devDependency install puts `simt` in
14
+ `node_modules/.bin`, not on a harness's PATH, so that entry runs nothing on
15
+ Claude — a non-2 exit is silent: no enforcement — and blocks every tool call
16
+ on Cursor, whose entry sets `failClosed: true`. The install wrote a command
17
+ that worked only on machines that happened to have the binary on PATH, which
18
+ are exactly the machines that least need the hook.
19
+
20
+ ## Ruling
21
+
22
+ 1. **Every harness config names the repo shim, never the binary.**
23
+ `agent-hooks install` writes `.simt-hooks/agent-hook` beside the git shims,
24
+ rendered with the same `renderLocator` block from `src/locate.mjs`, and
25
+ every entry's command is `<shim> <event> --harness <id>`. The shim takes its
26
+ arguments through (`agent-hook "$@"`), so one file serves every event and
27
+ every harness, and `--harness` stays explicit rather than detected.
28
+ 2. **`failClosed` is set only because the command is the shim.** Cursor keeps
29
+ `failClosed: true` on entries that point at the shim. It is never set on a
30
+ bare-PATH binary: that combination blocks every tool call on the machines
31
+ where the binary is not installed, which is exactly the machines the shim
32
+ exists for.
33
+ 3. **A shim that cannot resolve refuses.** When no binary is reachable the shim
34
+ exits 1 with a remedy, the way the git shims do. On Claude that is still a
35
+ non-2 exit — silent, no enforcement — and that limitation is accepted and
36
+ stated here rather than hidden: the shim fixes the machines where `simt`
37
+ is installed but not on PATH, not the machines where it is absent.
38
+
39
+ ## Consequences
40
+
41
+ - `ours()` recognises both spellings, so an install over a pre-shim config
42
+ migrates the entry in place instead of stacking a second one.
43
+ - The shim is journaled with the configs, so `undo` removes or restores it
44
+ with the run that wrote it.
45
+ - A hand-written bare-`simt` entry is the author's, not this tool's: `status`
46
+ does not claim it, and `install` replaces it.
@@ -0,0 +1,51 @@
1
+ ---
2
+ simt-affects: ["src/commands/agenthook.mjs", "src/commands/help.mjs", "test/agenthooks.test.mjs"]
3
+ simt-supersedes: []
4
+ ---
5
+
6
+ # ADR-107 — an install can be narrowed to one harness, and the skipped ones are named
7
+
8
+ Status: **accepted** · 2026-10-30
9
+
10
+ ## Context
11
+
12
+ `agent-hooks install` wrote every harness that documents a hooks file. A
13
+ repository whose agents run in one of them received entries in the others'
14
+ files as well — files no agent there reads, which a later `status` then
15
+ reports PRESENT while nothing in that harness enforces anything. For a
16
+ one-harness repository the install wrote more files than it needed to, and
17
+ there was no way to ask for fewer.
18
+
19
+ ADR-079 ruling 11 settled that the readers this tool does not write are
20
+ *named* in the report — a command that writes four files and stays silent
21
+ about the fifth reads as covering it. A narrowed install creates a third
22
+ category that ruling did not anticipate: readers this tool *can* write and
23
+ did not.
24
+
25
+ ## Ruling
26
+
27
+ 1. **`agent-hooks install --harness <id>` writes that one reader.** The id is
28
+ validated against the adapter table before anything is planned, and an
29
+ unknown id is a usage error that names the valid ids — the same validation
30
+ `agent-hook` applies, with the same remedy. The shim is written as before:
31
+ every config points at it, and a one-harness install would leave a config
32
+ pointing at a shim that is not there.
33
+ 2. **The skipped adapters are named in both surfaces.** The text report
34
+ prints a `SKIPPED` line per skipped reader with a note that says how to
35
+ write them all, and the JSON document carries them in `notWritten` with
36
+ `state: "skipped"`. A narrowed install that stays silent about the readers
37
+ it left alone is the failure ADR-079 ruling 11 ruled out for the full one.
38
+ 3. **`status` is unchanged.** It reports what each harness *will* run, and a
39
+ file that was never written is `ABSENT` there — the true answer. The
40
+ narrowing is a choice the install made, and the install's report is where
41
+ that choice is recorded.
42
+
43
+ ## Consequences
44
+
45
+ - A repository that installs for one harness and later adds a second runs
46
+ install again — with the new id, or without any — and the merge creates the
47
+ entry in the new file while the files it already wrote come back
48
+ `UNCHANGED`. Nothing about a narrowed install has to be undone.
49
+ - The prompt opt-in hint prints only when the selected harness can receive a
50
+ packet; a narrowed install to a harness with no prompt event does not ask
51
+ for an opt-in it cannot use.
@@ -0,0 +1,59 @@
1
+ ---
2
+ simt-affects: ["src/commands/init.mjs", "src/commands/map.mjs", "test/init.test.mjs", "test/map.test.mjs"]
3
+ simt-supersedes: []
4
+ ---
5
+
6
+ # ADR-108 — an adoption builds the index, and a command that reads it refreshes it on read
7
+
8
+ Status: **accepted** · 2026-10-30
9
+
10
+ ## Context
11
+
12
+ The index is a cache of git blobs (ADR-089): gitignored, rebuildable from
13
+ `git ls-files -s`, and the data source for `simt map`, `simt brief` and
14
+ `simt slice`. Two states of that cache were wrong for an adopted repository.
15
+
16
+ First, `simt init` adopted a repository and left the index unbuilt. The
17
+ first `simt map` in a fresh adoption paid for a walk of the whole tree, and
18
+ the prompt-submit hook delivered a cold index — "the index is empty" — until
19
+ somebody happened to run `simt index`. An adoption that promises the tool
20
+ works in that repository should leave it able to answer.
21
+
22
+ Second, once built, the cache went stale silently. `loadGraph` rebuilt only
23
+ when the index was *empty*, so a file added after the build was invisible to
24
+ every command that reads the index, with no way to tell from their output
25
+ that they were answering from an old tree.
26
+
27
+ ## Ruling
28
+
29
+ 1. **`init` builds the index in the apply phase**, after the manifest is
30
+ written — `reindex` reads it for the declared parsers, so the manifest has
31
+ to exist first. The plan names the file it will build, and the JSON
32
+ document carries the result. A failure is a *note*, not a failed adoption:
33
+ the index is a cache, and an adopted repository whose index build failed
34
+ is better than one that refused to be adopted for it. The next read
35
+ rebuilds what the apply could not.
36
+ 2. **A command that reads the index refreshes it on read.** `loadGraph` with
37
+ `build` (the default) reindexes from the git index before it reads. The
38
+ refresh is incremental — a blob that has not changed is not re-read — so
39
+ the cost of a current repository is one `git ls-files -s`, not a walk of
40
+ the tree. The callers that build are commands a person typed: `map`,
41
+ `brief`, `slice`.
42
+ 3. **The `build: false` callers are unchanged.** The prompt-submit hook (R29)
43
+ and the MCP surface report a cold index rather than build one: a delivered
44
+ packet that walked the whole repository would make a person's first prompt
45
+ in a fresh clone wait, and a prompt that takes a minute to appear is how a
46
+ hook gets uninstalled.
47
+
48
+ ## Consequences
49
+
50
+ - Amends ADR-091's consequence that "`simt map` reads the index and rebuilds
51
+ it when the cache is empty": the refresh now happens on every read, not
52
+ only on an empty one.
53
+ - In an adopted repository the prompt hook can deliver a packet from the
54
+ *first* prompt: `init` has already built the index, so R29's "the first
55
+ prompt gets nothing, the second gets the packet" no longer applies to a
56
+ repository that was adopted rather than cloned.
57
+ - `simt why` is unchanged: it deliberately does not write the cache to answer
58
+ a question, because writing a cache to answer a question would change the
59
+ tree.
@@ -0,0 +1,47 @@
1
+ ---
2
+ simt-affects: ["AGENTS.md", "rules/core.md", "rules/stacks/node.md", "rules/stacks/python.md", "rules/stacks/connectiq.md", "src/projection/project.mjs", "test/baselines.test.mjs", "test/upgrade.test.mjs"]
3
+ simt-supersedes: []
4
+ ---
5
+
6
+ # ADR-109 — simt-dev is its own consumer, and the guards that kept it from being one are retired
7
+
8
+ Status: **accepted** · 2026-10-30
9
+
10
+ ## Context
11
+
12
+ This repository ran `simt init` on itself, and the suite still believed the
13
+ opposite. Two tests asserted that simt-dev is *not* a consumer of itself — no
14
+ manifest, no region — and `AGENTS.md` explained why self-adoption was
15
+ impossible: the region's stamp records a SHA, so every commit would make the
16
+ file stale.
17
+
18
+ That explanation is no longer true. The `simt:sha=` stamp is a digest of the
19
+ rule *content* — `rules/` and the baselines — not of this repository's HEAD.
20
+ A commit here does not move it, so `check` stays green until the rule text
21
+ itself changes, and `simt sync --yes` re-renders it when that happens.
22
+
23
+ ## Ruling
24
+
25
+ 1. **This repository is a consumer of itself.** `simt.json` declares its
26
+ gates, and the generated region in `AGENTS.md` carries the rules it
27
+ projects. The two tests that asserted the opposite are rewritten to assert
28
+ the new state: the baselines exist with the region first, and an `upgrade`
29
+ from its own source is a no-op that moves no stamp.
30
+ 2. **The rule text names the manifest by the name that resolves in every
31
+ repository.** Four rule files said `simt-dev.json`, the pre-rename name;
32
+ ADR-056 reads both and writes the new one, so a reader in any repository
33
+ finds only `simt.json`. The text now says `simt.json`.
34
+ 3. **A gate finding whose `detail` is absent is `null`, not `undefined`.** A
35
+ key with an `undefined` value survives into the structured MCP surface but
36
+ is dropped by `JSON.stringify`, so the two surfaces of one answer no longer
37
+ deep-equal. The four constructions of a region verdict now share one helper
38
+ that emits `null`.
39
+
40
+ ## Consequences
41
+
42
+ - The suite's view of this repository is the adopted one: `check` here is
43
+ green until the rule content changes, and the baselines test asserts the
44
+ region-first placement that keeps a hand-written setting below it winning
45
+ (ADR-025).
46
+ - `AGENTS.md`'s hand-written section now says what is true: the repository
47
+ adopts itself, and the stamp is a content digest.