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.
- package/CHANGELOG.md +162 -841
- package/README.md +21 -135
- package/agents/simt-agent.md +84 -0
- package/bin/simt.mjs +19 -55
- package/docs/decisions/ADR-009-skill-layout.md +1 -1
- package/docs/decisions/ADR-014-workspace-is-configuration.md +1 -1
- package/docs/decisions/ADR-086-the-stable-prefix-comes-first-and-the-lock-records-both-digests.md +1 -1
- package/docs/decisions/ADR-099-the-release-verifies-served-bytes-and-the-formula-mirrors-them.md +1 -1
- package/docs/decisions/ADR-106-the-harness-hook-runs-through-a-repo-shim.md +46 -0
- package/docs/decisions/ADR-107-an-install-can-name-one-harness-and-the-skipped-ones-are-named.md +51 -0
- package/docs/decisions/ADR-108-an-adoption-builds-the-index-and-a-command-refreshes-it-on-read.md +59 -0
- 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
- 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
- package/docs/decisions/ADR-111-the-tool-ships-one-agent-rendered-per-harness-and-installs-it-with-init-and-a-command.md +75 -0
- package/docs/decisions/ADR-112-the-registry-is-what-simt-dev-ships-and-a-repo-owns-its-own-skills.md +81 -0
- package/docs/decisions/ADR-113-a-pre-push-that-carries-only-documentation-skips-the-test-gate-and-says-so.md +87 -0
- 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
- 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
- package/docs/decisions/ADR-116-rust-support-reaches-the-example-path-the-indent-and-the-bench-runner.md +100 -0
- package/docs/decisions/ADR-117-the-darwin-release-builds-on-supported-macos-15-runners-and-a-re-run-is-idempotent.md +81 -0
- 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
- package/docs/decisions/ADR-119-the-environment-variable-points-into-a-workspace-the-repo-declared.md +90 -0
- package/docs/decisions/ADR-120-a-pre-push-whose-tree-is-already-proven-green-skips-the-test-gate-on-that-evidence.md +96 -0
- package/docs/decisions/ADR-122-the-shims-move-into-the-state-directory-and-the-legacy-directory-removes-itself.md +94 -0
- package/docs/decisions/ADR-123-a-surplus-positional-is-not-refused-because-arity-is-not-in-the-source.md +57 -0
- package/docs/decisions/ADR-124-the-manifest-has-a-schema-in-the-tool-and-its-unknown-keys-stay-the-repositorys.md +64 -0
- package/docs/decisions/ADR-125-a-shared-context-belongs-to-a-read-and-a-writer-reads-directly.md +65 -0
- package/package.json +13 -3
- package/rules/core.md +9 -2
- package/rules/mdc/slice-commit.mdc +57 -4
- package/rules/mdc/test-gate.mdc +2 -0
- package/rules/stacks/android.md +3 -3
- package/rules/stacks/connectiq.md +2 -2
- package/rules/stacks/dart.md +1 -1
- package/rules/stacks/deno.md +1 -1
- package/rules/stacks/dotnet.md +1 -1
- package/rules/stacks/elixir.md +1 -1
- package/rules/stacks/go.md +1 -1
- package/rules/stacks/jvm.md +3 -2
- package/rules/stacks/node.md +2 -2
- package/rules/stacks/python.md +7 -6
- package/rules/stacks/ruby.md +1 -1
- package/rules/stacks/rust.md +1 -1
- package/rules/stacks/swift.md +1 -1
- package/rules/stacks/typescript.md +2 -2
- package/rules/stacks/uv.md +3 -2
- package/skills/simt-commands/SKILL.md +70 -0
- package/src/advice/advice.mjs +7 -3
- package/src/agenthooks/decide.mjs +141 -9
- package/src/agenthooks/opencode.mjs +72 -0
- package/src/agenthooks/prompt.mjs +10 -3
- package/src/agenthooks/render.mjs +186 -19
- package/src/agenthooks/shim.mjs +55 -0
- package/src/agents/render.mjs +277 -0
- package/src/api.mjs +29 -0
- package/src/argv.mjs +37 -3
- package/src/bench/ablate.mjs +31 -14
- package/src/bench/adapters.json +16 -0
- package/src/bench/corpus.mjs +150 -0
- package/src/bench/grade.mjs +23 -49
- package/src/bench/mine.mjs +247 -36
- package/src/bench/probes.mjs +104 -68
- package/src/bench/process.mjs +128 -0
- package/src/bench/report.mjs +260 -84
- package/src/bench/run.mjs +251 -150
- package/src/bench/variants.mjs +112 -40
- package/src/brief/assemble.mjs +44 -3
- package/src/ci/workflow.mjs +46 -14
- package/src/cli.mjs +45 -0
- package/src/commands/agent.mjs +205 -0
- package/src/commands/agenthook.mjs +113 -20
- package/src/commands/bench.mjs +192 -18
- package/src/commands/brief.mjs +5 -4
- package/src/commands/ci.mjs +2 -1
- package/src/commands/compare.mjs +50 -49
- package/src/commands/completions.mjs +2 -6
- package/src/commands/decide.mjs +10 -9
- package/src/commands/distill.mjs +4 -3
- package/src/commands/doctor.mjs +11 -7
- package/src/commands/evidence.mjs +19 -12
- package/src/commands/explain.mjs +0 -1
- package/src/commands/gate.mjs +98 -28
- package/src/commands/graph.mjs +20 -8
- package/src/commands/harness.mjs +3 -2
- package/src/commands/help.mjs +160 -31
- package/src/commands/hooks.mjs +163 -50
- package/src/commands/ignore.mjs +2 -1
- package/src/commands/impact.mjs +8 -9
- package/src/commands/index.mjs +278 -180
- package/src/commands/init.mjs +171 -38
- package/src/commands/lease.mjs +206 -39
- package/src/commands/lessons.mjs +72 -15
- package/src/commands/local.mjs +3 -3
- package/src/commands/map.mjs +47 -27
- package/src/commands/mcp.mjs +0 -1
- package/src/commands/pack.mjs +9 -6
- package/src/commands/plan.mjs +6 -5
- package/src/commands/plugin.mjs +3 -3
- package/src/commands/prbody.mjs +3 -3
- package/src/commands/repoindex.mjs +5 -3
- package/src/commands/review.mjs +2 -2
- package/src/commands/rules.mjs +124 -33
- package/src/commands/shared.mjs +2 -3
- package/src/commands/skills.mjs +82 -45
- package/src/commands/skillscompile.mjs +12 -12
- package/src/commands/skillsinstall.mjs +14 -2
- package/src/commands/slice.mjs +396 -26
- package/src/commands/spec.mjs +151 -0
- package/src/commands/status.mjs +4 -7
- package/src/commands/sync.mjs +50 -33
- package/src/commands/tests.mjs +11 -11
- package/src/commands/tokens.mjs +2 -2
- package/src/commands/undo.mjs +29 -31
- package/src/commands/upgrade.mjs +40 -4
- package/src/commands/why.mjs +19 -12
- package/src/compare/hooksstate.mjs +23 -1
- package/src/compare/learn.mjs +82 -57
- package/src/compare/parallel.mjs +50 -0
- package/src/compare/row.mjs +26 -3
- package/src/completions.mjs +5 -0
- package/src/context.mjs +64 -0
- package/src/decisions/dir.mjs +84 -0
- package/src/decisions/index-doc.mjs +46 -0
- package/src/decisions/index.mjs +109 -11
- package/src/diff.mjs +1 -1
- package/src/distill/distill.mjs +17 -2
- package/src/distill/engine.mjs +5 -1
- package/src/ecosystem/node-runner.mjs +144 -0
- package/src/explain.mjs +18 -6
- package/src/graph/load.mjs +42 -20
- package/src/hooks/capability.mjs +17 -4
- package/src/hooks/dispatcher.mjs +513 -36
- package/src/hooks/gates.mjs +0 -43
- package/src/hooks/resolve.mjs +11 -10
- package/src/hooks/shim.mjs +17 -9
- package/src/identity.mjs +96 -15
- package/src/index/extract.mjs +192 -11
- package/src/index/persist.mjs +307 -47
- package/src/index/store.mjs +263 -60
- package/src/index/tests.mjs +6 -35
- package/src/journal.mjs +372 -84
- package/src/kernel/card.mjs +37 -12
- package/src/kernel/checks.mjs +44 -9
- package/src/kernel/variants.mjs +27 -16
- package/src/lease.mjs +97 -15
- package/src/ledger/index.mjs +120 -25
- package/src/local/client.mjs +4 -6
- package/src/locate.mjs +33 -9
- package/src/manifest/schema.mjs +213 -0
- package/src/mcp/resources.mjs +12 -13
- package/src/mcp/server.mjs +151 -38
- package/src/mcp/tools.mjs +90 -16
- package/src/measure/session.mjs +3 -2
- package/src/memory/decide.mjs +98 -43
- package/src/memory/lessons.mjs +168 -33
- package/src/name.mjs +9 -0
- package/src/node-version.mjs +37 -0
- package/src/output/index.mjs +111 -3
- package/src/packs/manage.mjs +17 -3
- package/src/packs.mjs +20 -2
- package/src/plan/index.mjs +31 -8
- package/src/plan/template.mjs +27 -5
- package/src/plugins.mjs +6 -2
- package/src/prbody.mjs +7 -5
- package/src/projection/baselines.mjs +1 -1
- package/src/projection/disclosure.mjs +2 -2
- package/src/projection/loaders.mjs +41 -1
- package/src/projection/lock.mjs +31 -14
- package/src/projection/manifest.mjs +89 -53
- package/src/projection/markers.mjs +43 -3
- package/src/projection/mdc.mjs +34 -7
- package/src/projection/project.mjs +162 -18
- package/src/projection/rules.mjs +58 -6
- package/src/projection/surfaces.mjs +9 -1
- package/src/repo-root.mjs +88 -0
- package/src/resolve/body.mjs +4 -0
- package/src/resolve/fingerprint.mjs +24 -15
- package/src/resolve/local.mjs +58 -0
- package/src/review/critic.mjs +6 -3
- package/src/secrets.mjs +165 -22
- package/src/state.mjs +76 -0
- package/src/status.mjs +9 -4
- package/src/toolwords.mjs +8 -0
- package/src/tsconfig.mjs +39 -99
- package/src/workspace.mjs +55 -10
- package/templates/plan/tracker.json +1 -1
- package/docs/decisions/README.md +0 -591
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# simt-dev
|
|
2
2
|
|
|
3
|
-

|
|
4
|
+
|
|
5
|
+
[](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
|
-
|
|
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.
|
|
81
|
-
published `.sha256` before
|
|
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
|
|
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
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
|
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
|
|
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
|
-
//
|
|
2
|
+
// The entry point, and the one place the runtime floor is enforced.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
// the
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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-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
|
package/docs/decisions/ADR-086-the-stable-prefix-comes-first-and-the-lock-records-both-digests.md
CHANGED
|
@@ -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`
|
package/docs/decisions/ADR-099-the-release-verifies-served-bytes-and-the-formula-mirrors-them.md
CHANGED
|
@@ -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.
|
package/docs/decisions/ADR-107-an-install-can-name-one-harness-and-the-skipped-ones-are-named.md
ADDED
|
@@ -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.
|
package/docs/decisions/ADR-108-an-adoption-builds-the-index-and-a-command-refreshes-it-on-read.md
ADDED
|
@@ -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.
|