simt-dev 0.6.3 → 0.7.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 (137) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +2 -2
  3. package/agents/simt-agent.md +84 -0
  4. package/docs/decisions/ADR-009-skill-layout.md +1 -1
  5. package/docs/decisions/ADR-086-the-stable-prefix-comes-first-and-the-lock-records-both-digests.md +1 -1
  6. package/docs/decisions/ADR-106-the-harness-hook-runs-through-a-repo-shim.md +46 -0
  7. package/docs/decisions/ADR-107-an-install-can-name-one-harness-and-the-skipped-ones-are-named.md +51 -0
  8. package/docs/decisions/ADR-108-an-adoption-builds-the-index-and-a-command-refreshes-it-on-read.md +59 -0
  9. 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
  10. 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
  11. package/docs/decisions/ADR-111-the-tool-ships-one-agent-rendered-per-harness-and-installs-it-with-init-and-a-command.md +75 -0
  12. package/docs/decisions/ADR-112-the-registry-is-what-simt-dev-ships-and-a-repo-owns-its-own-skills.md +81 -0
  13. package/docs/decisions/ADR-113-a-pre-push-that-carries-only-documentation-skips-the-test-gate-and-says-so.md +87 -0
  14. 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
  15. 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
  16. package/docs/decisions/ADR-116-rust-support-reaches-the-example-path-the-indent-and-the-bench-runner.md +100 -0
  17. package/docs/decisions/README.md +9 -0
  18. package/package.json +4 -2
  19. package/rules/core.md +2 -2
  20. package/rules/mdc/test-gate.mdc +2 -0
  21. package/rules/stacks/android.md +3 -3
  22. package/rules/stacks/connectiq.md +2 -2
  23. package/rules/stacks/dart.md +1 -1
  24. package/rules/stacks/deno.md +1 -1
  25. package/rules/stacks/dotnet.md +1 -1
  26. package/rules/stacks/elixir.md +1 -1
  27. package/rules/stacks/go.md +1 -1
  28. package/rules/stacks/jvm.md +3 -2
  29. package/rules/stacks/node.md +2 -2
  30. package/rules/stacks/python.md +7 -6
  31. package/rules/stacks/ruby.md +1 -1
  32. package/rules/stacks/rust.md +1 -1
  33. package/rules/stacks/swift.md +1 -1
  34. package/rules/stacks/typescript.md +2 -2
  35. package/rules/stacks/uv.md +3 -2
  36. package/skills/simt-commands/SKILL.md +70 -0
  37. package/src/advice/advice.mjs +7 -3
  38. package/src/agenthooks/decide.mjs +141 -9
  39. package/src/agenthooks/opencode.mjs +72 -0
  40. package/src/agenthooks/prompt.mjs +6 -2
  41. package/src/agenthooks/render.mjs +186 -19
  42. package/src/agenthooks/shim.mjs +55 -0
  43. package/src/agents/render.mjs +277 -0
  44. package/src/argv.mjs +8 -0
  45. package/src/bench/ablate.mjs +31 -14
  46. package/src/bench/mine.mjs +48 -1
  47. package/src/bench/probes.mjs +5 -6
  48. package/src/bench/report.mjs +243 -80
  49. package/src/bench/run.mjs +12 -11
  50. package/src/bench/variants.mjs +112 -40
  51. package/src/brief/assemble.mjs +6 -0
  52. package/src/ci/workflow.mjs +16 -7
  53. package/src/commands/agent.mjs +206 -0
  54. package/src/commands/agenthook.mjs +109 -15
  55. package/src/commands/bench.mjs +2 -1
  56. package/src/commands/compare.mjs +8 -7
  57. package/src/commands/decide.mjs +6 -5
  58. package/src/commands/evidence.mjs +13 -3
  59. package/src/commands/gate.mjs +85 -19
  60. package/src/commands/graph.mjs +18 -5
  61. package/src/commands/help.mjs +35 -14
  62. package/src/commands/hooks.mjs +68 -25
  63. package/src/commands/impact.mjs +4 -2
  64. package/src/commands/index.mjs +17 -4
  65. package/src/commands/init.mjs +169 -37
  66. package/src/commands/lease.mjs +203 -35
  67. package/src/commands/lessons.mjs +65 -9
  68. package/src/commands/map.mjs +33 -18
  69. package/src/commands/plugin.mjs +1 -1
  70. package/src/commands/repoindex.mjs +1 -0
  71. package/src/commands/rules.mjs +92 -18
  72. package/src/commands/skills.mjs +60 -25
  73. package/src/commands/skillscompile.mjs +8 -7
  74. package/src/commands/skillsinstall.mjs +12 -0
  75. package/src/commands/slice.mjs +377 -18
  76. package/src/commands/sync.mjs +37 -22
  77. package/src/commands/tests.mjs +5 -2
  78. package/src/commands/undo.mjs +24 -16
  79. package/src/commands/upgrade.mjs +33 -1
  80. package/src/commands/why.mjs +10 -4
  81. package/src/compare/hooksstate.mjs +23 -1
  82. package/src/compare/learn.mjs +82 -57
  83. package/src/compare/parallel.mjs +50 -0
  84. package/src/compare/row.mjs +26 -1
  85. package/src/completions.mjs +5 -0
  86. package/src/decisions/dir.mjs +84 -0
  87. package/src/decisions/index.mjs +109 -11
  88. package/src/distill/distill.mjs +3 -1
  89. package/src/ecosystem/node-runner.mjs +144 -0
  90. package/src/explain.mjs +18 -6
  91. package/src/graph/load.mjs +38 -19
  92. package/src/hooks/capability.mjs +14 -1
  93. package/src/hooks/dispatcher.mjs +335 -13
  94. package/src/hooks/resolve.mjs +9 -3
  95. package/src/hooks/shim.mjs +12 -7
  96. package/src/identity.mjs +67 -14
  97. package/src/index/extract.mjs +192 -11
  98. package/src/index/persist.mjs +307 -47
  99. package/src/index/store.mjs +263 -60
  100. package/src/index/tests.mjs +6 -35
  101. package/src/journal.mjs +296 -77
  102. package/src/kernel/card.mjs +37 -12
  103. package/src/kernel/checks.mjs +44 -9
  104. package/src/kernel/variants.mjs +27 -16
  105. package/src/lease.mjs +97 -15
  106. package/src/ledger/index.mjs +91 -25
  107. package/src/mcp/resources.mjs +5 -3
  108. package/src/mcp/server.mjs +81 -22
  109. package/src/mcp/tools.mjs +45 -9
  110. package/src/memory/decide.mjs +98 -43
  111. package/src/memory/lessons.mjs +168 -33
  112. package/src/name.mjs +9 -0
  113. package/src/plan/index.mjs +31 -8
  114. package/src/plan/template.mjs +27 -5
  115. package/src/plugins.mjs +6 -2
  116. package/src/prbody.mjs +7 -5
  117. package/src/projection/baselines.mjs +1 -1
  118. package/src/projection/disclosure.mjs +2 -2
  119. package/src/projection/loaders.mjs +41 -1
  120. package/src/projection/lock.mjs +21 -14
  121. package/src/projection/manifest.mjs +69 -19
  122. package/src/projection/markers.mjs +43 -3
  123. package/src/projection/mdc.mjs +34 -7
  124. package/src/projection/project.mjs +162 -18
  125. package/src/projection/rules.mjs +54 -3
  126. package/src/projection/surfaces.mjs +9 -1
  127. package/src/repo-root.mjs +69 -0
  128. package/src/resolve/body.mjs +4 -0
  129. package/src/resolve/fingerprint.mjs +5 -0
  130. package/src/resolve/local.mjs +58 -0
  131. package/src/review/critic.mjs +4 -2
  132. package/src/secrets.mjs +165 -22
  133. package/src/state.mjs +76 -0
  134. package/src/status.mjs +9 -4
  135. package/src/toolwords.mjs +5 -0
  136. package/src/tsconfig.mjs +39 -99
  137. package/templates/plan/tracker.json +1 -1
package/CHANGELOG.md CHANGED
@@ -6,6 +6,41 @@ All notable changes to this package are recorded here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.7.0] — 2026-10-31
10
+
11
+ ### Added
12
+
13
+ `simt agent-hooks install --harness <id>` writes the policies into one
14
+ harness instead of all of them; an unknown id is a usage error that names
15
+ the valid ones. The readers the run skipped are named in the report
16
+ (`SKIPPED`) and in the JSON document's `notWritten`, so a narrowed install
17
+ cannot read as full coverage (ADR-107).
18
+
19
+ `simt init --yes` builds the repository index as part of the adoption, so
20
+ the first `simt map` or `simt brief` in a fresh repository answers from real
21
+ files. Commands that read the index (`map`, `brief`, `slice`) now refresh it
22
+ from the git index on every read — unchanged blobs are not re-read, so a
23
+ current repository pays for one `git ls-files -s` — and the prompt hook and
24
+ MCP surface still report a cold index rather than build one (ADR-108).
25
+
26
+ The rule text names the manifest as `simt.json`, the name it has had since
27
+ the rename; four rule files still said `simt-dev.json`, which resolves in no
28
+ repository.
29
+
30
+ ### Changed
31
+
32
+ The projection lock is `simt.lock.json`, the name that follows the command
33
+ and the manifest. A lock written under the old `simt-dev.lock.json` is still
34
+ read — including the `variants` winners nothing else records — and migrates
35
+ on the next write (ADR-110).
36
+
37
+ This repository is now a consumer of itself: `simt init` ran on its own
38
+ source, so the two tests that asserted it was *not* a consumer are rewritten
39
+ to assert the new state, and `AGENTS.md`'s "not self-adopted" section now
40
+ says what is true (ADR-109). A gate finding whose `detail` is absent is now
41
+ `null` rather than `undefined`, so the CLI's JSON and the MCP structured
42
+ surface of one answer deep-equal.
43
+
9
44
  ## [0.6.3] — 2026-10-29
10
45
 
11
46
  ### Added
package/README.md CHANGED
@@ -152,7 +152,7 @@ simt bench run --yes # evaluate arms (bare, current, kernel, brie
152
152
  simt bench report [--compare a b] # resolved rate, quality, cost, CPI, bootstrap CIs, McNemar/Wilcoxon
153
153
  simt bench ablate --yes # leave-one-out rule ablation ranked by value per KB
154
154
  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
155
+ simt bench variants --yes # evaluate simt-variants slots and lock winners in simt.lock.json
156
156
  simt review [--local] # an advisory ADR-008 verdict skeleton over the staged diff
157
157
  simt distill <skill|doc> # a budgeted proposal summary with line citations, for a person to merge
158
158
  simt pack new <name> --source <spec> # scaffold a versioned pack: pack.json, bench.json, one rule
@@ -369,7 +369,7 @@ history. All remain off until named and propose rather than write projected text
369
369
  | --- | --- |
370
370
  | `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
371
  | `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` |
372
+ | `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
373
  | `.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
374
  | `.editorconfig`, `.gitattributes` | baseline regions, placed first so a later setting still wins |
375
375
  | `.simt-hooks/` and `core.hooksPath` | the shared dispatcher. It fails closed |
@@ -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.
@@ -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-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`
@@ -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.
@@ -0,0 +1,43 @@
1
+ ---
2
+ simt-affects: ["src/name.mjs", "src/projection/lock.mjs", "src/kernel/variants.mjs", "src/commands/sync.mjs", "src/commands/help.mjs", "src/bench/variants.mjs", "test/lock.test.mjs", "test/variants.test.mjs"]
3
+ simt-supersedes: [{ adr: "ADR-086", ruling: 3, kind: "superseded" }]
4
+ ---
5
+
6
+ # ADR-110 — the lock is `simt.lock.json`, and the old name is read until the next write
7
+
8
+ Status: **accepted** · 2026-10-30 · supersedes ADR-086 ruling 3's file name
9
+
10
+ ## Context
11
+
12
+ The lock followed the command's old name: `simt-dev.lock.json`. The command
13
+ is `simt`, the manifest is `simt.json`, and the lock was the one remaining
14
+ file that still carried the pre-rename spelling.
15
+
16
+ A rename cannot be a bare move. A lock written by a pre-rename run may hold
17
+ `variants` winners that nothing else records — the bench evidence for a
18
+ locked rule text — so a reader that only knows the new name would silently
19
+ unlock those decisions.
20
+
21
+ ## Ruling
22
+
23
+ 1. **The lock is `simt.lock.json`.** The old name is a read-only fallback:
24
+ a reader tries the new name first and falls back to the old one, and a
25
+ write always lands under the new name, which is how a legacy lock
26
+ migrates. The fallback is for absence, not for damage: a permission
27
+ failure on the new name does not fall back, and a file that exists but
28
+ does not parse is reported, not repaired by an older file. This is the
29
+ same read-both/write-new pattern as the manifest rename (ADR-056).
30
+ 2. **The name lives in one place.** `src/name.mjs` owns both names, the way
31
+ it owns the manifest's. The kernel and the projection each carried a
32
+ private copy — the kernel cannot import the projection, because the
33
+ projection imports the kernel — and two constants for one file is how a
34
+ rename ships half-done.
35
+
36
+ ## Consequences
37
+
38
+ - A repository whose lock predates the rename keeps its locked variant
39
+ winners: `simt check --frozen` and the projection read them from the old
40
+ file, and the next `simt sync --yes` or `simt bench variants --yes` writes
41
+ them back under the new name.
42
+ - ADR-086's ruling 3 stands for what the lock records — an input digest and
43
+ an output digest; the file name it named is superseded.
@@ -0,0 +1,75 @@
1
+ ---
2
+ simt-affects: ["agents/simt-agent.md", "src/agents/render.mjs", "src/commands/agent.mjs", "src/commands/init.mjs", "src/projection/loaders.mjs", "src/toolwords.mjs", "test/agents.test.mjs"]
3
+ simt-supersedes: []
4
+ ---
5
+
6
+ # ADR-111 — the tool ships one agent, rendered per harness, and installs it with init and a command
7
+
8
+ Status: **accepted** · 2026-10-30
9
+
10
+ ## Context
11
+
12
+ The rules this tool projects tell an agent *what* to obey; nothing told it
13
+ *how to act* through the tool. The plan for that was two agents — a planner
14
+ and a builder — but the two jobs are one job in practice: read the tracker,
15
+ take the next slice, build it, test it, commit it. Two files that both say
16
+ "run the simt commands" are two copies of the same logic, and the second copy
17
+ is where the next divergence grows.
18
+
19
+ Six harnesses read a subagent and no two agree on the file. Five write a
20
+ markdown file with YAML frontmatter and a body that becomes the system
21
+ prompt; Codex writes a TOML file whose `developer_instructions` holds the
22
+ same body. The path, the extension, the frontmatter keys and the document
23
+ shape are all different, and none of them is the same fact.
24
+
25
+ A hooks entry is a config key the tool merges into a file it does not own.
26
+ An agent is a file the tool owns whole: there is nothing to merge, and the
27
+ only question is whether the bytes on disk are the bytes the tool would write
28
+ now.
29
+
30
+ ## Ruling
31
+
32
+ 1. **The tool ships one agent, `Simt-Agent`.** Its body is the system prompt
33
+ and it encodes how to act with simt-dev across the whole slice lifecycle —
34
+ orient (`simt brief`, `simt why`), plan (`simt plan status`, `simt plan
35
+ next`), build (`simt slice start`, the focused test, `simt slice finish`,
36
+ `simt plan done`) and the boundaries that hold everywhere. Planning and
37
+ building are one agent because they are one job.
38
+ 2. **The source of truth is one file, `agents/simt-agent.md`.** Neutral
39
+ frontmatter (`name`, `description`) plus a harness-agnostic body. The
40
+ renderer strips that frontmatter and re-emits the keys each harness
41
+ documents, so the body — the part that says how to act — is written once
42
+ and cannot drift between harnesses. The `simt-agent` stem is a name this
43
+ tool owns, and it is derived into the tool-word set from the module that
44
+ owns it, the way the other prefixed names are.
45
+ 3. **An agent is a file the tool owns whole, so the install is a byte
46
+ comparison.** `rendered` produces the text and reports `created`,
47
+ `unchanged` or `updated`. There is no parse that can fail and no partial
48
+ state, which is what makes the command shorter than `agent-hooks install`.
49
+ 4. **It is installed per harness, and the readers it does not write are
50
+ named.** Six harnesses document an agents file and receive one; the two
51
+ that document none are reported `NO FILE` with the reason, the way
52
+ ADR-079 ruling 11 requires. `--harness <id>` narrows the install to one
53
+ reader and names the skipped ones (ADR-107), and `status` reports
54
+ present, absent, drift, and the readers with no file.
55
+ 5. **It is written by `simt init` and by a separate `simt agents install`.**
56
+ `init` plans the agent files with the rest of the adoption and writes them
57
+ in the apply path, journaled the same way, so `undo` restores them with the
58
+ rest. The separate command exists for a repository that is already adopted
59
+ and wants only the agent, and for a narrowed install. Both call the same
60
+ `planAgents` and `writeAgentPlan`, so a dry run and a run describe the same
61
+ set of files.
62
+
63
+ ## Consequences
64
+
65
+ - A repository that is adopted and later upgrades the tool's agent body runs
66
+ `simt agents install --yes` (or re-runs `init`) and the files come back
67
+ `updated` with the new body; the frontmatter each harness documents is
68
+ re-emitted from the same source, so it cannot drift.
69
+ - The agent body names only commands a consumer repository runs — `simt
70
+ brief`, `simt why`, `simt plan`, `simt slice` — so every byte in it is
71
+ actionable in the receiving repository, the rule this repository exists to
72
+ enforce.
73
+ - `agents/` is published with the package: the tool reads its own agent body
74
+ from the installed copy, and a tarball without it would install cleanly and
75
+ then fail on the one command that writes the agent.
@@ -0,0 +1,81 @@
1
+ ---
2
+ simt-affects: ["graph/skills.graph.json", "src/resolve/local.mjs", "src/commands/skills.mjs", "src/projection/disclosure.mjs", "src/resolve/body.mjs"]
3
+ simt-supersedes: [{ adr: "ADR-009", ruling: 4 }]
4
+ ---
5
+
6
+ # ADR-112 — the registry is what simt-dev ships, and a repo owns its own skills
7
+
8
+ Status: **accepted** · 2026-10-31 · filed as S4 (plan 0005) · supersedes ADR-009 ruling 4
9
+
10
+ ## Context
11
+
12
+ ADR-009 settled the layout: a skill is `<name>/SKILL.md` with mandatory `name`
13
+ and `description` frontmatter, and body size and reference count are declared in
14
+ `graph/skills.graph.json`, "so the registry stays the single source of truth for
15
+ resolution metadata". The layout half of that ruling was about one estate's
16
+ thirty-nine skills, and the metadata half assumed the estate was the universe: a
17
+ skill not in the graph is a skill that does not exist.
18
+
19
+ Plan 0005 broke that assumption in two slices. S2 removed the thirty-one
20
+ repo-specific entries from the graph, leaving the eight skills this tool ships —
21
+ `simt-commands` and seven vendored stack skills. A graph that describes one
22
+ estate and is read by everyone was ADR-061's finding; a graph that is one
23
+ estate's whole skill population is a stronger claim ADR-061 did not make, and S2
24
+ made it false. S3 then gave the repo's own skill directories standing in the
25
+ resolver: `skills find`, `brief`, `show` and `why` answer for a skill the
26
+ registry never declared, synthesising its node from the file — name and summary
27
+ from frontmatter, size from the file, body from the path (commit 7d44071).
28
+
29
+ A reader of ADR-009 acting on the metadata sentence concludes that a skill absent
30
+ from the graph has no resolution metadata, and therefore cannot resolve. That
31
+ conclusion is now false in every repo that keeps its own skills, and a record
32
+ that says what the tool no longer believes is the failure this directory exists
33
+ to prevent.
34
+
35
+ ## Ruling
36
+
37
+ 1. **The graph is a catalogue of what simt-dev ships, not the sole home of
38
+ skills.** Membership in `graph/skills.graph.json` is a statement about the
39
+ package, not about existence. A skill a repository installed in its own skill
40
+ directories exists and resolves with no entry in the graph.
41
+ 2. **A repo's skill directories are a first-class source of resolution.**
42
+ Presence is the eligibility signal — a skill the repo installed is about the
43
+ repo, and the stack it belongs to is the stack the repo has. Frontmatter
44
+ supplies the name and the summary; the file supplies the body and the size.
45
+ This is the mechanism S3 shipped; the ruling records it so the reader learns
46
+ what the tool believes without reading the plan.
47
+ 3. **Where a name is in both, the registry entry is canonical.** The graph entry
48
+ and the local file are one skill — the file is the installed copy of what the
49
+ graph declares — and keeping both would rank one skill twice. The graph wins
50
+ the dedupe; the local node is dropped, not merged.
51
+
52
+ ## Consequences
53
+
54
+ - ADR-009's layout ruling stands and is load-bearing: discovery reads `name` and
55
+ `description` from frontmatter, so a local skill without them is invisible,
56
+ which is the defect class ADR-009 exists to prevent. What moves is the metadata
57
+ sentence: a local skill's resolution metadata is synthesised from the
58
+ filesystem, not read from the graph, so the graph is no longer the single
59
+ source of truth for it.
60
+ - `skills find`, `brief`, `show` and `why` answer for names the registry never
61
+ declared. The NOT SELECTED block no longer points a reader at a `skills show
62
+ <name>` that 404s for a name the graph does not carry.
63
+ - Nothing in the shipped bytes changes. ADR-061 stands as written: the registry
64
+ is workspace data, the package ships none of it, and a command that finds no
65
+ registry says so. This record settles the half ADR-061 left open — who is
66
+ allowed to have skills the catalogue does not name — without touching its
67
+ rulings.
68
+ - `skills index` keeps reporting the catalogue only: it is the tier-0 view of
69
+ what this tool ships, and local skills surface where a repo is the context,
70
+ which is `find` and `brief`.
71
+
72
+ ## Rejected
73
+
74
+ - **Rewrite ADR-009 in place.** The supersession rule this directory opens with
75
+ is a new record and an edited status line, never a rewritten ruling. ADR-009's
76
+ audit data — the forty-six frontmatter tallies that found the flat file — is
77
+ evidence its own ruling relies on, the same shape that kept ADR-011 standing
78
+ when ADR-012 reversed it.
79
+ - **Annotate ADR-009 without a record.** The supersession is a claim about what
80
+ the tool believes, and a claim without a record is a ruling nobody can cite.
81
+ The annotation points at ADR-112; ADR-112 carries the argument.