@turri-dev/cli 0.1.4-next.5a94e68 → 0.1.4-next.67734c0

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 (40) hide show
  1. package/README.md +39 -127
  2. package/dist/extension.js +11 -17
  3. package/dist/regenerate/side-panel.js +1 -1
  4. package/docs/README.md +5 -12
  5. package/docs/authoring-plain.md +37 -119
  6. package/docs/config.md +50 -176
  7. package/docs/deploy.md +21 -80
  8. package/docs/development.md +13 -41
  9. package/docs/headless.md +30 -136
  10. package/docs/installation.md +13 -40
  11. package/docs/parser.md +15 -43
  12. package/docs/regenerating.md +231 -964
  13. package/docs/sandbox.md +38 -152
  14. package/docs/skills-and-gates.md +50 -173
  15. package/docs/theming.md +45 -46
  16. package/docs/using.md +66 -356
  17. package/genome/rules/bullet-continuation.md +5 -13
  18. package/genome/rules/concise-specs-examples.md +2 -4
  19. package/genome/rules/concise-specs-integration-examples.md +2 -6
  20. package/genome/rules/concise-specs.md +1 -2
  21. package/genome/rules/func-specs.md +1 -0
  22. package/genome/rules/integration-embedded-testing.md +1 -4
  23. package/genome/rules/integrations.md +1 -2
  24. package/genome/rules/project-model.md +14 -35
  25. package/genome/rules/stdlib.md +14 -49
  26. package/genome/rules/turri-regeneration.md +48 -0
  27. package/genome/skills/add-implementation-requirement/SKILL.md +1 -2
  28. package/genome/skills/analyze-if-func-spec-too-complex/SKILL.md +3 -8
  29. package/genome/skills/brood/SKILL.md +37 -127
  30. package/genome/skills/brood/references/intent.md +4 -12
  31. package/genome/skills/brood/references/product.md +24 -76
  32. package/genome/skills/brood/references/stack.md +7 -29
  33. package/genome/skills/brood/references/testing.md +11 -42
  34. package/genome/skills/bud/SKILL.md +32 -109
  35. package/genome/skills/bud/references/intent.md +4 -11
  36. package/genome/skills/implement-conformance-testing-script/SKILL.md +3 -6
  37. package/genome/skills/implement-unit-testing-script/SKILL.md +1 -2
  38. package/genome/skills/mature/SKILL.md +21 -69
  39. package/genome/skills/spawn/SKILL.md +28 -113
  40. package/package.json +1 -1
package/docs/config.md CHANGED
@@ -1,16 +1,8 @@
1
1
  # The project config
2
2
 
3
- A project says how its specs are built in `config.turri.yaml`, at the project root. Everything in it
4
- is optional: with no file at all, turri finds the testing scripts on its own, turns conformance
5
- tests on wherever a module has test reqs, and runs on pi's configured model. A project whose
6
- parts are on different stacks - a backend and a frontend - adds a file per stack,
7
- `config.turri.<stack>.yaml`, beside it, and chooses the stack to build with (see
8
- [stacks](#stacks)). turri never writes a `config.yaml`: it may be another tool's, and
9
- is read only by a project that has no file of turri's yet (see [the old config.yaml](#the-old-configyaml)).
10
-
11
- `turri init-config` starts one: the two models, a strong one to talk to and a smaller one to write the code. It
12
- asks which vendor's models you use - `--vendor` says it without asking, and with neither, as from a script, it is
13
- `other`:
3
+ A project says how its specs are built in `config.turri.yaml`, at the project root. Everything in it is optional: with no file at all, turri finds the testing scripts on its own, turns conformance tests on wherever a module has test reqs, and runs on pi's configured model. A project whose parts are on different stacks - a backend and a frontend - adds a file per stack, `config.turri.<stack>.yaml`, beside it, and chooses the stack to build with (see [stacks](#stacks)). turri never writes a `config.yaml`: it may be another tool's, and is read only by a project that has no file of turri's yet (see [the old config.yaml](#the-old-configyaml)).
4
+
5
+ `turri init-config` starts one: the two models, a strong one to talk to and a smaller one to write the code. It asks which vendor's models you use - `--vendor` says it without asking, and with neither, as from a script, it is `other`:
14
6
 
15
7
  | vendor | harness-model | coding-model | key pi reads |
16
8
  | --- | --- | --- | --- |
@@ -21,64 +13,30 @@ asks which vendor's models you use - `--vendor` says it without asking, and with
21
13
  | `amazon-bedrock`, OpenAI | `amazon-bedrock/<region>.openai.gpt-6-astra` | `amazon-bedrock/<region>.openai.gpt-6-luna` | `AWS_PROFILE` or `AWS_BEARER_TOKEN_BEDROCK`, and `AWS_REGION` |
22
14
  | `other` | `anthropic/claude-opus-5-5` | `google/gemini-3.1-flash-lite` | `ANTHROPIC_API_KEY`, `GEMINI_API_KEY` |
23
15
 
24
- Amazon Bedrock asks two more things - whose models, Anthropic's or OpenAI's (`--maker`), and the region of the
25
- inference profile they run in (`--region`): `global`, `us`, `eu`, `jp` or `au` for Anthropic's, `global` or `us` for
26
- OpenAI's. It says which `AWS_REGION` to set for it - pi calls Bedrock in `us-east-1` when none is. A `config.turri.yaml`
27
- already there keeps everything but its two models, which it sets; `--force` writes the whole file again.
28
-
29
- Each is written with how hard it thinks - `harness-model: openai/gpt-6-astra:medium`, `coding-model:
30
- openai/gpt-6-luna:low` - so the file shows it. The reviews and judges run on the coding model but think medium (see
31
- [models per role](#models-per-role)).
32
-
33
- They are an example, not a requirement - any model [pi](https://pi.dev) supports works, signed in any way pi
34
- supports; `other` is the starting point for another provider. What we recommend is that split, a capable model to
35
- talk to and a smaller, cheaper one for the coding. Once written, it says what to do next: the key to set in your
36
- shell - or `/login` in turri, which pi keeps in `~/.pi/agent/auth.json` - and that the file belongs to that folder:
37
- turri reads the nearest `config.turri.yaml` upwards from where it starts, so one written anywhere else is not seen.
38
-
39
- Below them it writes every other setting out, each with what it does and the value turri uses for it - `review: false`,
40
- `turn-limit: 120`, `parallel-jobs` as this machine's cores make it - so the file says how the project is built, and you
41
- change one by changing it. The optional ones, which have no value of their own - the testing scripts (written in by the
42
- skill that writes them), `module`, `conformance-budget`, `judge-model`, `models` - are there commented out, each with an
43
- example: uncomment one to use it. A key taken out of the file is still read as the table below says.
44
-
45
- Beside a `config.yaml` - another tool's, say - the new file takes from it the keys turri reads too, each in its place, its
46
- testing scripts above all, and says which it left (see [the old config.yaml](#the-old-configyaml)); `config.yaml`
47
- is left as it is. A `config.turri.yaml` already there keeps everything but its two models, which it sets - `--force` writes the whole
48
- file again - and a `config.yaml` turri read until then is copied to it first. It takes a folder other than the current
49
- one as its argument.
16
+ Amazon Bedrock asks two more things - whose models, Anthropic's or OpenAI's (`--maker`), and the region of the inference profile they run in (`--region`): `global`, `us`, `eu`, `jp` or `au` for Anthropic's, `global` or `us` for OpenAI's. It says which `AWS_REGION` to set for it - pi calls Bedrock in `us-east-1` when none is. A `config.turri.yaml` already there keeps everything but its two models, which it sets; `--force` writes the whole file again.
17
+
18
+ Each is written with how hard it thinks - `harness-model: openai/gpt-6-astra:medium`, `coding-model: openai/gpt-6-luna:low` - so the file shows it. The reviews and judges run on the coding model but think medium (see [models per role](#models-per-role)).
19
+
20
+ They are an example, not a requirement - any model [pi](https://pi.dev) supports works, signed in any way pi supports; `other` is the starting point for another provider. What we recommend is that split, a capable model to talk to and a smaller, cheaper one for the coding. Once written, it says what to do next: the key to set in your shell - or `/login` in turri, which pi keeps in `~/.pi/agent/auth.json` - and that the file belongs to that folder: turri reads the nearest `config.turri.yaml` upwards from where it starts, so one written anywhere else is not seen.
21
+
22
+ Below them it writes every other setting out, each with what it does and the value turri uses for it - `review: false`, `turn-limit: 120`, `parallel-jobs` as this machine's cores make it - so the file says how the project is built, and you change one by changing it. The optional ones, which have no value of their own - the testing scripts (written in by the skill that writes them), `module`, `conformance-budget`, `judge-model`, `models` - are there commented out, each with an example: uncomment one to use it. A key taken out of the file is still read as the table below says.
23
+
24
+ Beside a `config.yaml` - another tool's, say - the new file takes from it the keys turri reads too, each in its place, its testing scripts above all, and says which it left (see [the old config.yaml](#the-old-configyaml)); `config.yaml` is left as it is. A `config.turri.yaml` already there keeps everything but its two models, which it sets - `--force` writes the whole file again - and a `config.yaml` turri read until then is copied to it first. It takes a folder other than the current one as its argument.
50
25
 
51
26
  ## Where it is read from
52
27
 
53
- A spec belongs to its **project**: the nearest folder, from the spec's own folder up, that holds a
54
- `config.turri.yaml`, a stack's `config.turri.<stack>.yaml`, the old `config.yaml` or a `plain_modules/`.
55
- Without any of them, the spec's own folder is the project. That folder's config is the one read, and
56
- its `plain_modules/` is where the code is built, wherever turri was started. So a project that keeps
57
- its specs in `plain/`, with `plain/config.turri.yaml`, builds `plain/app.plain` by
58
- `plain/config.turri.yaml` even when `turri` runs in the folder above.
28
+ A spec belongs to its **project**: the nearest folder, from the spec's own folder up, that holds a `config.turri.yaml`, a stack's `config.turri.<stack>.yaml`, the old `config.yaml` or a `plain_modules/`. Without any of them, the spec's own folder is the project. That folder's config is the one read, and its `plain_modules/` is where the code is built, wherever turri was started. So a project that keeps its specs in `plain/`, with `plain/config.turri.yaml`, builds `plain/app.plain` by `plain/config.turri.yaml` even when `turri` runs in the folder above.
59
29
 
60
30
  When it is read:
61
31
 
62
- - **In the chat**, afresh: the chat's agent is told what it says on every turn, and each render
63
- reads it when it is queued. An edit to the file holds from the next turn and the next render, with
64
- no restart. The agent is told the config of the session's folder and of the projects one folder
65
- down.
66
- - **On the command line**, once, when the command starts. `turri regenerate` takes `module:` from
67
- the folder it is run in, and the rest from the spec's own project.
32
+ - **In the chat**, afresh: the chat's agent is told what it says on every turn, and each render reads it when it is queued. An edit to the file holds from the next turn and the next render, with no restart. The agent is told the config of the session's folder and of the projects one folder down.
33
+ - **On the command line**, once, when the command starts. `turri regenerate` takes `module:` from the folder it is run in, and the rest from the spec's own project.
68
34
 
69
35
  ## Changing it from the chat
70
36
 
71
- `/turri-config` changes any key in the chat, and writes it into the `config.turri.yaml` of the folder turri was started in -
72
- its comments, and the commented-out examples, kept. Alone, it lists every key with what it is now, and asks for the
73
- value of the one you pick the way the key takes it: `true` or `false`, one of its words, a number from a few offered or
74
- typed, a model from those this machine can reach and then how hard it thinks, a script or a `.plain` file the project
75
- has, rules ticked on and off. `/turri-config review` asks for review's value; `/turri-config review false` sets it, and
76
- `/turri-config review unset` takes it out, back to its default. Completion offers the keys, then each one's values.
77
- Each role's model and turn limit is `models.<role>` and `models.<role>.turn-limit` - `models.coding`,
78
- `models.planner.turn-limit`.
37
+ `/turri-config` changes any key in the chat, and writes it into the `config.turri.yaml` of the folder turri was started in - its comments, and the commented-out examples, kept. Alone, it lists every key with what it is now, and asks for the value of the one you pick the way the key takes it: `true` or `false`, one of its words, a number from a few offered or typed, a model from those this machine can reach and then how hard it thinks, a script or a `.plain` file the project has, rules ticked on and off. `/turri-config review` asks for review's value; `/turri-config review false` sets it, and `/turri-config review unset` takes it out, back to its default. Completion offers the keys, then each one's values. Each role's model and turn limit is `models.<role>` and `models.<role>.turn-limit` - `models.coding`, `models.planner.turn-limit`.
79
38
 
80
- Each change says when it takes effect. None needs turri started again - what turri fixes as it starts is changed as it
81
- runs:
39
+ Each change says when it takes effect. None needs turri started again - what turri fixes as it starts is changed as it runs:
82
40
 
83
41
  | when | keys |
84
42
  | --- | --- |
@@ -90,10 +48,7 @@ runs:
90
48
  | the next pulse that lands - the running one too | `release-after-pulse` |
91
49
  | the next regeneration that names no `.plain` file | `module` |
92
50
 
93
- A coding model chosen this session - `--coding-model`, or `engine` - gives way to one set here: the last word wins. It
94
- says, too, what wins over the change: `models.chat` over `harness-model` (and so on), and a stack's
95
- `config.turri.<stack>.yaml`, which is not changed here, while that stack is chosen. In a project still read from
96
- `config.yaml`, the first change copies it to `config.turri.yaml` first - see [the old config.yaml](#the-old-configyaml).
51
+ A coding model chosen this session - `--coding-model`, or `engine` - gives way to one set here: the last word wins. It says, too, what wins over the change: `models.chat` over `harness-model` (and so on), and a stack's `config.turri.<stack>.yaml`, which is not changed here, while that stack is chosen. In a project still read from `config.yaml`, the first change copies it to `config.turri.yaml` first - see [the old config.yaml](#the-old-configyaml).
97
52
 
98
53
  ## The keys
99
54
 
@@ -145,15 +100,11 @@ models: # each agent role's model, thinking and tur
145
100
  | `models` | each agent role's own model, thinking and turn limit - see [models per role](#models-per-role) | every role on `coding-model`, the conversation's side on `harness-model` |
146
101
  | `testing-scripts-run-on` | what the testing scripts run on - always on this machine, in your environment. `in-place`: the real build and tests folders, the script at its own path, from the project - so a script that finds a host codebase from its own path finds it. `copy`: a fresh copy of the code, staged in `plain_modules/.turri/scripts/`, with the script copied beside it. `can_it_fail` works on either: on a copy it changes the copy, in place the code itself for the one run, put back after it (see [the testing scripts](regenerating.md#the-testing-scripts)) | `in-place` |
147
102
 
148
- Keys are written with dashes; underscores are read the same (`conformance_tests`). A key turri
149
- does not know is ignored - another tool's `config.yaml`, read while it is the old file, may carry several - and so is a value of the
150
- wrong type, as if it were not there. `model:`, from before there were separate models, is read as
151
- `coding-model`.
103
+ Keys are written with dashes; underscores are read the same (`conformance_tests`). A key turri does not know is ignored - another tool's `config.yaml`, read while it is the old file, may carry several - and so is a value of the wrong type, as if it were not there. `model:`, from before there were separate models, is read as `coding-model`.
152
104
 
153
105
  ## Models per role
154
106
 
155
- `models:` gives each kind of agent its own model, thinking level and turn limit. Each entry is a model
156
- (`provider/id`, or `provider/id:thinking`) or `{ model, thinking, turn-limit }`, any of which may be left out:
107
+ `models:` gives each kind of agent its own model, thinking level and turn limit. Each entry is a model (`provider/id`, or `provider/id:thinking`) or `{ model, thinking, turn-limit }`, any of which may be left out:
157
108
 
158
109
  | role | the agents |
159
110
  | --- | --- |
@@ -171,37 +122,21 @@ wrong type, as if it were not there. `model:`, from before there were separate m
171
122
  | `arbiter` | the arbiters that weigh a second review |
172
123
  | `debugger` | the fresh look at unit tests that keep failing the same way, or a coding agent going round in circles. Unnamed, `judge-model` when it is set, else the harness model - not `default` |
173
124
 
174
- What an entry leaves out it takes from `default`: `reviewer: { thinking: low }` runs the default model, thinking
175
- little. A turn limit is the role's own, else `default`'s, else `turn-limit:`, else two minutes. A stack's `config.turri.<stack>.yaml` lays its own `models:` over the project's, role by role - all but
176
- `chat`, the project's alone.
125
+ What an entry leaves out it takes from `default`: `reviewer: { thinking: low }` runs the default model, thinking little. A turn limit is the role's own, else `default`'s, else `turn-limit:`, else two minutes. A stack's `config.turri.<stack>.yaml` lays its own `models:` over the project's, role by role - all but `chat`, the project's alone.
177
126
 
178
- A role whose thinking nothing names - neither its entry, `default`'s, nor a `:level` on the model it runs on - thinks
179
- as its kind of work needs: **low** for the agents that do the work (`coding`, `conformance`, `explorer`, `release`),
180
- which work from specs that leave little to guess and take many turns, and **medium** for the ones that judge
181
- (`reviewer`, `test-reviewer`, `judge`, `arbiter`, `debugger`, `planner`, `chooser`, `diagnosis`), where a wrong
182
- call costs pulses. A judging role that falls back on the coding model takes its model alone, not its thinking. The
183
- conversation keeps its own level, as pi sets it.
127
+ A role whose thinking nothing names - neither its entry, `default`'s, nor a `:level` on the model it runs on - thinks as its kind of work needs: **low** for the agents that do the work (`coding`, `conformance`, `explorer`, `release`), which work from specs that leave little to guess and take many turns, and **medium** for the ones that judge (`reviewer`, `test-reviewer`, `judge`, `arbiter`, `debugger`, `planner`, `chooser`, `diagnosis`), where a wrong call costs pulses. A judging role that falls back on the coding model takes its model alone, not its thinking. The conversation keeps its own level, as pi sets it.
184
128
 
185
- The thinking level reaches the model as each provider takes it. OpenAI's models on Bedrock are sent it as their
186
- reasoning effort (`none`, `low`, `medium`, `high`, `xhigh`) by turri itself, as pi sends them none.
129
+ The thinking level reaches the model as each provider takes it. OpenAI's models on Bedrock are sent it as their reasoning effort (`none`, `low`, `medium`, `high`, `xhigh`) by turri itself, as pi sends them none.
187
130
 
188
131
  ## How many jobs at once
189
132
 
190
- Jobs on the same module, or on modules of one `requires` chain, always run one after another.
191
- Modules that share nothing - a backend, a frontend, a worker, ten of them - build side by side, each
192
- pulse's builds and tests running on this machine beside your own work. So the chat runs at most `parallel-jobs` jobs
193
- at once; a job whose turn has come waits for a free slot past that, and its line says so. Unset, it is half this
194
- machine's cores, at least one and at most four. The config is the only place it is set. It is the project's alone,
195
- never read from a stack's file.
133
+ Jobs on the same module, or on modules of one `requires` chain, always run one after another. Modules that share nothing - a backend, a frontend, a worker, ten of them - build side by side, each pulse's builds and tests running on this machine beside your own work. So the chat runs at most `parallel-jobs` jobs at once; a job whose turn has come waits for a free slot past that, and its line says so. Unset, it is half this machine's cores, at least one and at most four. The config is the only place it is set. It is the project's alone, never read from a stack's file.
196
134
 
197
- The testing scripts all run on this machine, each on a copy of its module's code, so they never
198
- share files - but they do share its network: two modules whose conformance scripts start a server
199
- on the same port collide when they run at once. Give each its own.
135
+ The testing scripts all run on this machine, each on a copy of its module's code, so they never share files - but they do share its network: two modules whose conformance scripts start a server on the same port collide when they run at once. Give each its own.
200
136
 
201
137
  ## Models
202
138
 
203
- Each model is a model reference and a thinking level - `off`, `minimal`, `low`, `medium`, `high`,
204
- `xhigh` or `max` - and either may be left out:
139
+ Each model is a model reference and a thinking level - `off`, `minimal`, `low`, `medium`, `high`, `xhigh` or `max` - and either may be left out:
205
140
 
206
141
  ```yaml
207
142
  coding-model:
@@ -211,9 +146,7 @@ judge-model: google/gemini-3.1-pro:high # the same, as one string
211
146
  harness-model: anthropic/claude-opus-5-5 # a model alone
212
147
  ```
213
148
 
214
- What a model leaves out it takes from the one it inherits: `judge-model` from `coding-model` - its model, not its
215
- thinking, which the judging roles have their own of - and `coding-model` from `harness-model`. So with only a harness model, everything runs on it;
216
- `coding-model: {thinking: low}` renders on the harness model, thinking less.
149
+ What a model leaves out it takes from the one it inherits: `judge-model` from `coding-model` - its model, not its thinking, which the judging roles have their own of - and `coding-model` from `harness-model`. So with only a harness model, everything runs on it; `coding-model: {thinking: low}` renders on the harness model, thinking less.
217
150
 
218
151
  They are defaults. What is asked for wins over them:
219
152
 
@@ -223,52 +156,31 @@ They are defaults. What is asked for wins over them:
223
156
  | coding | `turri --coding-model <m>`, `engine` in the conversation |
224
157
  | judge | - |
225
158
 
226
- `turri regenerate`, `conform` and `spec-diff` read `--harness-model`, `--coding-model` (or `--model`),
227
- `--judge-model`, `--review` and `--conformance-tests` differently: as the keys themselves, as if the file had
228
- them. Each takes its key's value and its place in the order above - a `models:` entry still wins over it - so a
229
- headless run is the same as a chat with those keys in the file.
159
+ `turri regenerate`, `conform` and `spec-diff` read `--harness-model`, `--coding-model` (or `--model`), `--judge-model`, `--review` and `--conformance-tests` differently: as the keys themselves, as if the file had them. Each takes its key's value and its place in the order above - a `models:` entry still wins over it - so a headless run is the same as a chat with those keys in the file.
230
160
 
231
161
  A job keeps the model it was queued with: choosing another holds for what is queued after.
232
162
 
233
163
  ## Conformance tests
234
164
 
235
- `conformance-tests:` is the one switch, and the chat, every render and `brood`'s testing phase
236
- follow it. `false` turns them off entirely: no conformance tests are written, the ones already in a
237
- codebase are not run, and no agent is shown the conformance testing script. No key is the same as
238
- `false`: conformance tests are off by default. `all` (or `true`) means on wherever a module has
239
- `***test reqs***` - a module without them has nothing to write conformance tests from, so it writes
240
- none, but still keeps the codebase's existing ones passing. Asked in the
241
- conversation (`conform`), or with `--conformance-tests all|chosen|module|false` on `turri regenerate` and
242
- `spec-diff` - for that run, the file left as it is - a render does otherwise.
165
+ `conformance-tests:` is the one switch, and the chat, every render and `brood`'s testing phase follow it. `false` turns them off entirely: no conformance tests are written, the ones already in a codebase are not run, and no agent is shown the conformance testing script. No key is the same as `false`: conformance tests are off by default. `all` (or `true`) means on wherever a module has `***test reqs***` - a module without them has nothing to write conformance tests from, so it writes none, but still keeps the codebase's existing ones passing. Asked in the conversation (`conform`), or with `--conformance-tests all|chosen|module|false` on `turri regenerate` and `spec-diff` - for that run, the file left as it is - a render does otherwise.
243
166
 
244
- `spawn` writes `conformance-tests: false` into a new project unless you ask for tests;
245
- `brood` asks, whatever the key says, offering what it says first.
167
+ `spawn` writes `conformance-tests: false` into a new project unless you ask for tests; `brood` asks, whatever the key says, offering what it says first.
246
168
 
247
169
  ## The testing scripts
248
170
 
249
- A build needs a unit testing script - and, with conformance on, a conformance testing script - to
250
- decide when it is done. They are looked for at the project root, in this order:
171
+ A build needs a unit testing script - and, with conformance on, a conformance testing script - to decide when it is done. They are looked for at the project root, in this order:
251
172
 
252
173
  1. named in the config - the chosen stack's file first, then `config.turri.yaml` - by path from the root;
253
174
  2. the one `run_unittests*.sh` / `run_conformance_tests*.sh` in the project root;
254
175
  3. the one of each in `test_scripts/`.
255
176
 
256
- The optional prepare script - `prepare-environment-script:`, else the one `prepare_environment*.sh` - is looked for the
257
- same way, and run on the build before the conformance testing script.
177
+ The optional prepare script - `prepare-environment-script:`, else the one `prepare_environment*.sh` - is looked for the same way, and run on the build before the conformance testing script.
258
178
 
259
- A folder holding two of a kind is not guessed between: name the one to use. A script named inside
260
- `plain_modules/` is refused - agents write there, so it could be changed by the work it judges. The
261
- scripts are never linked from the specs. What they are and how they run is in
262
- [regenerating the code](regenerating.md#the-testing-scripts).
179
+ A folder holding two of a kind is not guessed between: name the one to use. A script named inside `plain_modules/` is refused - agents write there, so it could be changed by the work it judges. The scripts are never linked from the specs. What they are and how they run is in [regenerating the code](regenerating.md#the-testing-scripts).
263
180
 
264
181
  ## Credentials for the agents
265
182
 
266
- An agent's commands do not get the environment turri was started in: it holds your providers' API keys, cloud
267
- credentials and tokens. They get only the path, the locale, the terminal and the user, the variables that locate your
268
- toolchains (`JAVA_HOME`, `NVM_DIR`, `RUSTUP_HOME`, ... - the ones in your home found even when your shell sets none),
269
- and turri's own: a home folder of the module's own (`plain_modules/.turri/home/<module>`, kept between pulses, with a
270
- git identity of its own), a `TMPDIR`, the package caches in `plain_modules/.turri/cache`, and git stopped at the module
271
- folder, so a project that is itself a repository is never found from the code.
183
+ An agent's commands do not get the environment turri was started in: it holds your providers' API keys, cloud credentials and tokens. They get only the path, the locale, the terminal and the user, the variables that locate your toolchains (`JAVA_HOME`, `NVM_DIR`, `RUSTUP_HOME`, ... - the ones in your home found even when your shell sets none), and turri's own: a home folder of the module's own (`plain_modules/.turri/home/<module>`, kept between pulses, with a git identity of its own), a `TMPDIR`, the package caches in `plain_modules/.turri/cache`, and git stopped at the module folder, so a project that is itself a repository is never found from the code.
272
184
 
273
185
  A project whose agents need a credential while they work names it:
274
186
 
@@ -278,24 +190,13 @@ agent-env:
278
190
  vars: [D365_TENANT_ID] # these variables, from the environment turri was started in
279
191
  ```
280
192
 
281
- What it names reaches every agent with a shell, as environment variables of its commands only - the file stays where
282
- it is, outside every agent's reach - and never replaces turri's own home, `TMPDIR` or caches. A stack's file adds
283
- to the project's. A file that is not there, or a variable unset or empty, is reported as missing. The testing scripts
284
- are not affected: they run in your own environment.
193
+ What it names reaches every agent with a shell, as environment variables of its commands only - the file stays where it is, outside every agent's reach - and never replaces turri's own home, `TMPDIR` or caches. A stack's file adds to the project's. A file that is not there, or a variable unset or empty, is reported as missing. The testing scripts are not affected: they run in your own environment.
285
194
 
286
- Their values never appear in what an agent is shown or what turri writes: each is replaced by its name -
287
- `[D365_CLIENT_SECRET]` - whole, URL-encoded, or split over a command's output as it streams: in every tool result and
288
- refusal an agent is given (and so in the session transcripts, which hold only those), in the whole outputs kept for
289
- `read_output`, and in the job and debug logs. A value shorter than four characters is not masked - `1` or `eu` is
290
- everywhere in ordinary output.
195
+ Their values never appear in what an agent is shown or what turri writes: each is replaced by its name - `[D365_CLIENT_SECRET]` - whole, URL-encoded, or split over a command's output as it streams: in every tool result and refusal an agent is given (and so in the session transcripts, which hold only those), in the whole outputs kept for `read_output`, and in the job and debug logs. A value shorter than four characters is not masked - `1` or `eu` is everywhere in ordinary output.
291
196
 
292
197
  ## Stacks
293
198
 
294
- One project can hold parts that share nothing but a common module - a Python backend and a React
295
- frontend side by side, each importing `base` from `template/`, neither requiring the other - each
296
- needing its own testing scripts. Each stack gets a file of its own beside `config.turri.yaml`,
297
- `config.turri.<stack>.yaml`, holding what differs for it - typically its testing scripts, its
298
- `toolchains:`, its models:
199
+ One project can hold parts that share nothing but a common module - a Python backend and a React frontend side by side, each importing `base` from `template/`, neither requiring the other - each needing its own testing scripts. Each stack gets a file of its own beside `config.turri.yaml`, `config.turri.<stack>.yaml`, holding what differs for it - typically its testing scripts, its `toolchains:`, its models:
299
200
 
300
201
  ```
301
202
  config.turri.yaml # the project's: harness-model, coding-model, conformance-tests
@@ -317,50 +218,23 @@ coding-model:
317
218
 
318
219
  A stack is chosen, never worked out from the spec:
319
220
 
320
- - **In the chat**, with `/stack` - a list of the project's stacks and none - or `/stack backend`, `/stack none`.
321
- The chat's model has a `stack` tool too, and switches the stack when you ask it to, or for work on a part another
322
- stack builds. `/stack` alone says which is chosen now.
323
- - **On the command line**, with `--stack <name>` on any command - `turri regenerate`, `conform`, `spec-diff`, `glimpse`,
324
- `release`, `cultivate` - and on `turri --stack backend` for the chat; or with `TURRI_STACK` in the environment.
221
+ - **In the chat**, with `/stack` - a list of the project's stacks and none - or `/stack backend`, `/stack none`. The chat's model has a `stack` tool too, and switches the stack when you ask it to, or for work on a part another stack builds. `/stack` alone says which is chosen now.
222
+ - **On the command line**, with `--stack <name>` on any command - `turri regenerate`, `conform`, `spec-diff`, `glimpse`, `release`, `cultivate` - and on `turri --stack backend` for the chat; or with `TURRI_STACK` in the environment.
325
223
 
326
- The choice lasts for the session only: nothing remembers it, and turri started again has none chosen. A stack the
327
- project has no file for is refused, with the stacks it has. With none chosen, `config.turri.yaml` alone is used.
224
+ The choice lasts for the session only: nothing remembers it, and turri started again has none chosen. A stack the project has no file for is refused, with the stacks it has. With none chosen, `config.turri.yaml` alone is used.
328
225
 
329
226
  How a stack's config is made:
330
227
 
331
- - **Laid over `config.turri.yaml`, key by key.** What the stack's file gives wins; what it leaves out
332
- is the project's. A model it names takes what it leaves out from the project's same model - above,
333
- with the stack frontend chosen, everything renders on the project's coding model, thinking `high`.
334
- - **For everything built while it is chosen.** Every pulse that starts, every test run and every
335
- script found from then on is the chosen stack's; a pulse already running keeps the stack it
336
- started with. Choose the stack before building the part it is for: `/stack backend`, then
337
- `regenerate backend.plain`.
338
- - **The project's alone.** `module:`, `harness-model:`, `parallel-jobs:`, `rules-off:` and `compact-at:` are read
339
- only from `config.turri.yaml` - there is one conversation, one module built when none is named, one machine.
340
- `agent-env:` and `toolchains:` in a stack's file add to the project's.
341
-
342
- The chat is told each stack's config and the one chosen. The skills that write testing scripts put
343
- each stack's in its own file once a project has two stacks, and say which stack to choose before
344
- building each part.
228
+ - **Laid over `config.turri.yaml`, key by key.** What the stack's file gives wins; what it leaves out is the project's. A model it names takes what it leaves out from the project's same model - above, with the stack frontend chosen, everything renders on the project's coding model, thinking `high`.
229
+ - **For everything built while it is chosen.** Every pulse that starts, every test run and every script found from then on is the chosen stack's; a pulse already running keeps the stack it started with. Choose the stack before building the part it is for: `/stack backend`, then `regenerate backend.plain`.
230
+ - **The project's alone.** `module:`, `harness-model:`, `parallel-jobs:`, `rules-off:` and `compact-at:` are read only from `config.turri.yaml` - there is one conversation, one module built when none is named, one machine. `agent-env:` and `toolchains:` in a stack's file add to the project's.
231
+
232
+ The chat is told each stack's config and the one chosen. The skills that write testing scripts put each stack's in its own file once a project has two stacks, and say which stack to choose before building each part.
345
233
 
346
234
  ## The old config.yaml
347
235
 
348
- turri's settings were once in `config.yaml`, and a stack's in `config.<stack>.yaml`. A `config.yaml`
349
- may be another tool's, so turri never writes one. While a project folder has no `config.turri*.yaml`
350
- at all, turri still reads its `config.yaml`, and each `config.<name>.yaml` as the stack `<name>`.
351
-
352
- The first time turri itself writes a setting there with `/turri-config`, it copies `config.yaml` to
353
- `config.turri.yaml` and each `config.<name>.yaml` to `config.turri.<name>.yaml` first, leaves the old
354
- files as they are, and from then on reads only the new ones. `turri init-config` copies the stacks'
355
- files the same way, but writes `config.turri.yaml` as its quick start, taking from `config.yaml` only
356
- the keys turri reads too - `unittests-script`, `conformance-tests-script` and
357
- `prepare-environment-script`, say - each in its place in the file, and saying which keys it left:
358
- `template_dir`, `verbose`, `api`, the other tool's alone. The two models are the vendor's, never taken. To change a
359
- setting by hand in such a project, do the same: copy the files to their new names, and edit the
360
- copies - never `config.yaml`. Writing a `config.turri.yaml` of your own beside it is the same move: from then on
361
- `config.yaml` is not read, its testing scripts with it. For a headless run that only needs conformance tests or
362
- another judge, or review, those options leave the files alone: `--conformance-tests`, `--judge-model`, `--review true|false`, and the models' too.
363
-
364
- Keys turri does not read - another tool's `verbose`, `api-key`, `build-folder`, ... - are ignored without a word, and so
365
- is a value of the wrong type. A file that does not parse as YAML is read as empty, so its testing scripts are then
366
- looked for by name.
236
+ turri's settings were once in `config.yaml`, and a stack's in `config.<stack>.yaml`. A `config.yaml` may be another tool's, so turri never writes one. While a project folder has no `config.turri*.yaml` at all, turri still reads its `config.yaml`, and each `config.<name>.yaml` as the stack `<name>`.
237
+
238
+ The first time turri itself writes a setting there with `/turri-config`, it copies `config.yaml` to `config.turri.yaml` and each `config.<name>.yaml` to `config.turri.<name>.yaml` first, leaves the old files as they are, and from then on reads only the new ones. `turri init-config` copies the stacks' files the same way, but writes `config.turri.yaml` as its quick start, taking from `config.yaml` only the keys turri reads too - `unittests-script`, `conformance-tests-script` and `prepare-environment-script`, say - each in its place in the file, and saying which keys it left: `template_dir`, `verbose`, `api`, the other tool's alone. The two models are the vendor's, never taken. To change a setting by hand in such a project, do the same: copy the files to their new names, and edit the copies - never `config.yaml`. Writing a `config.turri.yaml` of your own beside it is the same move: from then on `config.yaml` is not read, its testing scripts with it. For a headless run that only needs conformance tests or another judge, or review, those options leave the files alone: `--conformance-tests`, `--judge-model`, `--review true|false`, and the models' too.
239
+
240
+ Keys turri does not read - another tool's `verbose`, `api-key`, `build-folder`, ... - are ignored without a word, and so is a value of the wrong type. A file that does not parse as YAML is read as empty, so its testing scripts are then looked for by name.
package/docs/deploy.md CHANGED
@@ -1,95 +1,41 @@
1
1
  # Trying what is built: deploy
2
2
 
3
- Ask to try it - "let me try it", "run the app" - at any time, even while a render is running. The
4
- chat calls `deploy`: it puts the module's code, as it was last built, in `dist/<module>` in the
5
- project, and starts it on your machine. An app with a backend and a frontend is started whole, and
6
- you are told where to open your browser. For a command-line tool or a library you get a few commands
7
- to paste, run from `dist/<module>`, and what they print.
3
+ Ask to try it - "let me try it", "run the app" - at any time, even while a render is running. The chat calls `deploy`: it puts the module's code, as it was last built, in `dist/<module>` in the project, and starts it on your machine. An app with a backend and a frontend is started whole, and you are told where to open your browser. For a command-line tool or a library you get a few commands to paste, run from `dist/<module>`, and what they print.
8
4
 
9
- Every pulse that lands code - a render, a spec diff, a conformance run, a functionality regenerated - ends with
10
- "Want to try it? Just ask me - I'll set it up from what's built so far." When a render's conformance
11
- tests follow as a pulse of their own, the conformance pulse says it, once they pass too.
5
+ Every pulse that lands code - a render, a spec diff, a conformance run, a functionality regenerated - ends with "Want to try it? Just ask me - I'll set it up from what's built so far." When a render's conformance tests follow as a pulse of their own, the conformance pulse says it, once they pass too.
12
6
 
13
7
  ## When the project says how it is released
14
8
 
15
- Every release starts the same way: the module's last commit - what last landed whole - goes in
16
- `dist/<module>`, as below. Not everything is tried from there, though. An integration that a host
17
- application loads goes on into the host's own tree, with the host's own scripts, and then the host
18
- is started. So the model asks itself whether there is guidance for how this project is released -
19
- in what you said, the project's AGENTS.md, a skill, anything it was given - and passes it to
20
- `release` whole:
21
-
22
- - **There is guidance.** The code goes on from `dist/<module>` as the guidance says, on your machine,
23
- from the host codebase - the git repository the project is in, or else where **turri** runs: the
24
- scripts it names, in their order, and any change it says the host needs. The code is taken from
25
- `dist`, never from `plain_modules`, where a pulse may be writing; where the host's tooling reads
26
- `plain_modules` itself, the model points it at `dist`, or does by hand from `dist` what it does. When
27
- to release - after every pulse, say - is the guidance's to say too. The rules below hold as they do for `dist`: the
28
- model runs the project's scripts and installs what they need itself, and what keeps running - a
29
- start script, a server - is started with `activate`. Nothing built is changed.
9
+ Every release starts the same way: the module's last commit - what last landed whole - goes in `dist/<module>`, as below. Not everything is tried from there, though. An integration that a host application loads goes on into the host's own tree, with the host's own scripts, and then the host is started. So the model asks itself whether there is guidance for how this project is released - in what you said, the project's AGENTS.md, a skill, anything it was given - and passes it to `release` whole:
10
+
11
+ - **There is guidance.** The code goes on from `dist/<module>` as the guidance says, on your machine, from the host codebase - the git repository the project is in, or else where **turri** runs: the scripts it names, in their order, and any change it says the host needs. The code is taken from `dist`, never from `plain_modules`, where a pulse may be writing; where the host's tooling reads `plain_modules` itself, the model points it at `dist`, or does by hand from `dist` what it does. When to release - after every pulse, say - is the guidance's to say too. The rules below hold as they do for `dist`: the model runs the project's scripts and installs what they need itself, and what keeps running - a start script, a server - is started with `activate`. Nothing built is changed.
30
12
  - **There is none.** The default: it is started from `dist/<module>`, as below, as best it can be.
31
13
 
32
- Guidance is whatever says it, in any words - a line in AGENTS.md such as *integrations are released
33
- with `scripts/deploy_integrations.sh`, then the app is started with `scripts/start.sh`*, or the
34
- same said in the chat.
14
+ Guidance is whatever says it, in any words - a line in AGENTS.md such as *integrations are released with `scripts/deploy_integrations.sh`, then the app is started with `scripts/start.sh`*, or the same said in the chat.
35
15
 
36
- The chat reacts to every pulse that finishes as it finishes, without waiting for you to speak: guidance
37
- that says to release after a build - *release each integration once it is regenerated* - is followed then.
38
- It never has to work out whether what a pulse landed is already out: `release` does. When the module's
39
- last commit is what its last release in this conversation shipped, it does nothing - nothing exported,
40
- nothing stopped, what runs left running - and says so; `again: true` releases it anyway, for when what
41
- that release said to do was not done.
16
+ The chat reacts to every pulse that finishes as it finishes, without waiting for you to speak: guidance that says to release after a build - *release each integration once it is regenerated* - is followed then. It never has to work out whether what a pulse landed is already out: `release` does. When the module's last commit is what its last release in this conversation shipped, it does nothing - nothing exported, nothing stopped, what runs left running - and says so; `again: true` releases it anyway, for when what that release said to do was not done.
42
17
 
43
18
  ## What goes in dist
44
19
 
45
- - **The module on top.** Code accumulates up a `requires` chain: a module starts from a copy of the
46
- code of the one it requires. So deploy always takes the module on top of the spec's chain - the
47
- project's `module` from `config.turri.yaml` unless another spec is named. Before the module on top has
48
- anything built, it takes the nearest one below it that has, and says so.
49
- - **Its last commit.** Each `plain_modules/<module>` is a git repository (`.plaingit`), and every unit
50
- of work starts from a commit and ends with one. What a pulse is writing right now is half-done, so it
51
- is left out: deploy exports the commit - `git archive` of `code/` - which is the working tree with
52
- every unstaged and untracked change put back, and no `node_modules`, `.venv`, `target` or other
53
- build leftovers, whatever the stack. The working tree the pulse is using is never read or touched.
54
- The harness's own files - `.turri.json`, the agents' notes - are left out too.
55
- - **Replaced whole.** Each deploy stops what the last one of the module started, empties
56
- `dist/<module>` and exports again. Change nothing there you want to keep. `dist/` is not added to
57
- `.gitignore`: whether it is committed is yours to decide.
20
+ - **The module on top.** Code accumulates up a `requires` chain: a module starts from a copy of the code of the one it requires. So deploy always takes the module on top of the spec's chain - the project's `module` from `config.turri.yaml` unless another spec is named. Before the module on top has anything built, it takes the nearest one below it that has, and says so.
21
+ - **Its last commit.** Each `plain_modules/<module>` is a git repository (`.plaingit`), and every unit of work starts from a commit and ends with one. What a pulse is writing right now is half-done, so it is left out: deploy exports the commit - `git archive` of `code/` - which is the working tree with every unstaged and untracked change put back, and no `node_modules`, `.venv`, `target` or other build leftovers, whatever the stack. The working tree the pulse is using is never read or touched. The harness's own files - `.turri.json`, the agents' notes - are left out too.
22
+ - **Replaced whole.** Each deploy stops what the last one of the module started, empties `dist/<module>` and exports again. Change nothing there you want to keep. `dist/` is not added to `.gitignore`: whether it is committed is yours to decide.
58
23
 
59
24
  ## Starting it
60
25
 
61
- It runs on your machine, outside the [sandbox](sandbox.md) - with your toolchains, where your
62
- browser can reach it. The chat reads how the code runs (its README, manifests and entry points),
63
- then:
64
-
65
- 1. **Checks the toolchains** it needs (`node`, `python3`, `go`, ...). One is missing: it installs it
66
- with the machine's package manager (`brew` on macOS, `apt` or `dnf` on Linux).
67
- 2. **Installs what it needs itself.** Dependencies into a virtual environment or `node_modules`, a
68
- build that downloads packages, an image pull, a guided release's project scripts: it runs them in
69
- its own shell, as any agent with a shell would, and fixes what fails. Nothing is put to you - there
70
- is no dialog to answer.
71
- 3. **Starts what serves** with `activate`: in the background, in its own process group, its
72
- output in `.turri/deploy/<module>-<name>.log`. It waits until something answers at the
73
- server's URL - up to a minute - so the URL you are given has answered once; one that exits first
74
- comes back with the end of its output. A port something else holds is said, with what holds it,
75
- and nothing is started there: the app is not moved to a port you were not told about.
76
-
77
- What it started is listed by the `pulses` tool and by **`/halt`**, and stopped by **`/halt activated <name>`**, by
78
- `halt`, by the next deploy of the module, and when the chat exits.
26
+ It runs on your machine, outside the [sandbox](sandbox.md) - with your toolchains, where your browser can reach it. The chat reads how the code runs (its README, manifests and entry points), then:
27
+
28
+ 1. **Checks the toolchains** it needs (`node`, `python3`, `go`, ...). One is missing: it installs it with the machine's package manager (`brew` on macOS, `apt` or `dnf` on Linux).
29
+ 2. **Installs what it needs itself.** Dependencies into a virtual environment or `node_modules`, a build that downloads packages, an image pull, a guided release's project scripts: it runs them in its own shell, as any agent with a shell would, and fixes what fails. Nothing is put to you - there is no dialog to answer.
30
+ 3. **Starts what serves** with `activate`: in the background, in its own process group, its output in `.turri/deploy/<module>-<name>.log`. It waits until something answers at the server's URL - up to a minute - so the URL you are given has answered once; one that exits first comes back with the end of its output. A port something else holds is said, with what holds it, and nothing is started there: the app is not moved to a port you were not told about.
31
+
32
+ What it started is listed by the `pulses` tool and by **`/halt`**, and stopped by **`/halt activated <name>`**, by `halt`, by the next deploy of the module, and when the chat exits.
79
33
 
80
34
  ## After every pulse
81
35
 
82
- With `release-after-pulse: true` in `config.turri.yaml`, turri releases what each pulse lands itself, as the
83
- pulse's last stage (`releasing what this pulse landed`): the pulse ends once it is released, so the
84
- module's next pulse starts on what is out, and the chat - waiting on your answer to a question, say - has
85
- no part in it. One release a pulse that lands, in order.
36
+ With `release-after-pulse: true` in `config.turri.yaml`, turri releases what each pulse lands itself, as the pulse's last stage (`releasing what this pulse landed`): the pulse ends once it is released, so the module's next pulse starts on what is out, and the chat - waiting on your answer to a question, say - has no part in it. One release a pulse that lands, in order.
86
37
 
87
- The release is done by an agent on the coding model, thinking low - it follows steps, and a small model does that
88
- well - the same one `turri release` runs, and it finds
89
- the guidance as the chat would: what was passed to `release` earlier in the conversation, the project's
90
- AGENTS.md and its skills. When nothing there says to release after a build, it releases nothing and says
91
- so. Its last words go in the pulse's report - "Released after the pulse: ..." - and the chat, seeing them,
92
- does not release it again. A release that fails is said there too; what the pulse landed stays.
38
+ The release is done by an agent on the coding model, thinking low - it follows steps, and a small model does that well - the same one `turri release` runs, and it finds the guidance as the chat would: what was passed to `release` earlier in the conversation, the project's AGENTS.md and its skills. When nothing there says to release after a build, it releases nothing and says so. Its last words go in the pulse's report - "Released after the pulse: ..." - and the chat, seeing them, does not release it again. A release that fails is said there too; what the pulse landed stays.
93
39
 
94
40
  Off by default: without the key, releasing after a pulse is the chat's, when its guidance says so.
95
41
 
@@ -99,11 +45,6 @@ Off by default: without the key, releasing after a pulse is the chat's, when its
99
45
  turri release [file.plain] [--in-module <module>] [--guidance <text>] [--model <provider/id>]
100
46
  ```
101
47
 
102
- The same, without the chat: a one-off agent on `coding-model`, thinking low (or `--model`; without either,
103
- pi's default) is given the project's AGENTS.md and what `--guidance <text>` says, looks for guidance in
104
- them, and releases as above - as the guidance says, or to `dist/<module>` - then works out how to
105
- start it and starts it here, installing what it needs without asking. It stays in the foreground with the servers'
106
- output; `Ctrl-C` stops them. If it does not get there, deploy from the chat instead.
48
+ The same, without the chat: a one-off agent on `coding-model`, thinking low (or `--model`; without either, pi's default) is given the project's AGENTS.md and what `--guidance <text>` says, looks for guidance in them, and releases as above - as the guidance says, or to `dist/<module>` - then works out how to start it and starts it here, installing what it needs without asking. It stays in the foreground with the servers' output; `Ctrl-C` stops them. If it does not get there, deploy from the chat instead.
107
49
 
108
- `turri regenerate`, `spec-diff` and `conform` end a build that landed with
109
- `To try it: turri release <spec>`.
50
+ `turri regenerate`, `spec-diff` and `conform` end a build that landed with `To try it: turri release <spec>`.
@@ -5,48 +5,26 @@ npm run typecheck # types
5
5
  npm test # the whole suite, about a minute
6
6
  ```
7
7
 
8
- The suite runs the projects' testing scripts on this machine, as turri does. The fixture scripts stage each run in a
9
- folder of their own, as test files running side by side would otherwise share one.
8
+ The suite runs the projects' testing scripts on this machine, as turri does. The fixture scripts stage each run in a folder of their own, as test files running side by side would otherwise share one.
10
9
 
11
10
  ## Mutation testing
12
11
 
13
- `npm run mutation` runs [Stryker](https://stryker-mutator.io) over the core of regeneration - the parts in
14
- `stryker.config.mjs` - one part at a time, each part's report in `reports/mutation/<part>/`. A part with a report is
15
- skipped, so a run that is stopped goes on from the part it was in; `npm run mutation -- <part>` runs one again, and
16
- `npm run mutation -- --summary` sums up the reports there are. It takes hours: each part runs the suite once to find
17
- which tests reach which mutant (`vitest.stryker.config.ts`, the suite without the files that run real commands behind the sandbox), then each
18
- mutant against those tests. `scripts/mutation.mjs` sets two things in Stryker's vitest runner the suite needs - forked
19
- workers, and a test-name filter that matches vitest 5's names - again after every `npm install`.
12
+ `npm run mutation` runs [Stryker](https://stryker-mutator.io) over the core of regeneration - the parts in `stryker.config.mjs` - one part at a time, each part's report in `reports/mutation/<part>/`. A part with a report is skipped, so a run that is stopped goes on from the part it was in; `npm run mutation -- <part>` runs one again, and `npm run mutation -- --summary` sums up the reports there are. It takes hours: each part runs the suite once to find which tests reach which mutant (`vitest.stryker.config.ts`, the suite without the files that run real commands behind the sandbox), then each mutant against those tests. `scripts/mutation.mjs` sets two things in Stryker's vitest runner the suite needs - forked workers, and a test-name filter that matches vitest 5's names - again after every `npm install`.
20
13
 
21
- The `mutation` workflow (`.github/workflows/mutation.yml`) runs it on GitHub, started by hand: Actions, mutation, Run
22
- workflow. It takes the parts to run, space-separated (empty for every part), each a job of its own side by side, on
23
- four cores (`TURRI_MUTATION_CONCURRENCY`; six here). Each part's `mutation.html` and `mutation.json` are uploaded as an
24
- artifact, `mutation-<part>`, and summed up on the run's page. Stryker's incremental file is cached from run to run, so
25
- a run tests again only the mutants whose code or tests changed; tick `fresh` to test every one again.
14
+ The `mutation` workflow (`.github/workflows/mutation.yml`) runs it on GitHub, started by hand: Actions, mutation, Run workflow. It takes the parts to run, space-separated (empty for every part), each a job of its own side by side, on four cores (`TURRI_MUTATION_CONCURRENCY`; six here). Each part's `mutation.html` and `mutation.json` are uploaded as an artifact, `mutation-<part>`, and summed up on the run's page. Stryker's incremental file is cached from run to run, so a run tests again only the mutants whose code or tests changed; tick `fresh` to test every one again.
26
15
 
27
- Working on turri itself, `npm link` points the global `turri` at this clone, so edits
28
- take effect immediately. `npm run chat` starts pi with the extension loaded from `src/`.
16
+ Working on turri itself, `npm link` points the global `turri` at this clone, so edits take effect immediately. `npm run chat` starts pi with the extension loaded from `src/`.
29
17
 
30
- The package on npm is built: Node runs no `.ts` file inside a `node_modules`, so `npm run build` (`scripts/build.mjs`,
31
- over `tsconfig.build.json`) compiles `src/` into `dist/`, file for file - each file as deep as its source, so it finds
32
- `genome/`, `stdlib/` and `.pi/` the same way - with its imports' `.ts` rewritten to `.js`, and copies the other files
33
- in `src/` beside them. `npm pack` and `npm publish` run it first (`prepack`), and the package holds `dist/`, not
34
- `src/`. `bin/turri.mjs` runs `src/cli.ts` where there is one and `dist/cli.js` otherwise; `cli.ts` starts pi with
35
- the launcher and extension beside itself, whichever they are. To try the package as users get it:
36
- `npm pack`, then `npm install -g ./turri-dev-cli-<version>.tgz`.
18
+ The package on npm is built: Node runs no `.ts` file inside a `node_modules`, so `npm run build` (`scripts/build.mjs`, over `tsconfig.build.json`) compiles `src/` into `dist/`, file for file - each file as deep as its source, so it finds `genome/`, `stdlib/` and `.pi/` the same way - with its imports' `.ts` rewritten to `.js`, and copies the other files in `src/` beside them. `npm pack` and `npm publish` run it first (`prepack`), and the package holds `dist/`, not `src/`. `bin/turri.mjs` runs `src/cli.ts` where there is one and `dist/cli.js` otherwise; `cli.ts` starts pi with the launcher and extension beside itself, whichever they are. To try the package as users get it: `npm pack`, then `npm install -g ./turri-dev-cli-<version>.tgz`.
37
19
 
38
20
  ## Publishing
39
21
 
40
22
  `.github/workflows/publish.yml` publishes `@turri-dev/cli`, after the typecheck and the suite pass:
41
23
 
42
- - every push or merge into `main` publishes a prerelease under the `next` dist-tag - the patch after the `latest` on
43
- npm, with the commit's sha: `0.1.2-next.<sha>`. `latest` is not touched; `npm install -g @turri-dev/cli@next` gets it.
44
- - a GitHub Release tagged `vX.Y.Z`, published by hand, publishes `X.Y.Z` as `latest` (or under `next`, if the release
45
- is marked a pre-release). The tag is the version: it is set in the runner and never committed, so `package.json`'s
46
- version on `main` is stale by design.
24
+ - every push or merge into `main` publishes a prerelease under the `next` dist-tag - the patch after the `latest` on npm, with the commit's sha: `0.1.2-next.<sha>`. `latest` is not touched; `npm install -g @turri-dev/cli@next` gets it.
25
+ - a GitHub Release tagged `vX.Y.Z`, published by hand, publishes `X.Y.Z` as `latest` (or under `next`, if the release is marked a pre-release). The tag is the version: it is set in the runner and never committed, so `package.json`'s version on `main` is stale by design.
47
26
 
48
- The workflow signs in to npm with npm's trusted publishing (OIDC), not a token: the package's settings on npmjs.com
49
- trust `turri-oss/turri`, the workflow `publish.yml` and the environment `npm`. Renaming the workflow file breaks it.
27
+ The workflow signs in to npm with npm's trusted publishing (OIDC), not a token: the package's settings on npmjs.com trust `turri-oss/turri`, the workflow `publish.yml` and the environment `npm`. Renaming the workflow file breaks it.
50
28
 
51
29
  ## Layout
52
30
 
@@ -82,14 +60,8 @@ trust `turri-oss/turri`, the workflow `publish.yml` and the environment `npm`. R
82
60
 
83
61
  ## Known edges
84
62
 
85
- - Judges default to the executor's model. Real separation wants a different provider - set
86
- `model:` on the gate. An unconfigured model falls back to the executor's with a note rather than
87
- failing the run.
88
- - The executor keeps one session across steps and retries, so context builds up with attempts. Long
89
- skills want compaction or a session per step.
90
- - A gate's escalation lives in memory (LangGraph's `MemorySaver`): it must be answered in the same
91
- run.
92
- - The gate machinery has no automated coverage; see
93
- [trying the gate semantics](skills-and-gates.md#trying-the-gate-semantics).
94
- - Jobs live in memory: there is no resuming a job after pi exits. The work itself is on disk, so a
95
- killed job leaves a partial build rather than nothing.
63
+ - Judges default to the executor's model. Real separation wants a different provider - set `model:` on the gate. An unconfigured model falls back to the executor's with a note rather than failing the run.
64
+ - The executor keeps one session across steps and retries, so context builds up with attempts. Long skills want compaction or a session per step.
65
+ - A gate's escalation lives in memory (LangGraph's `MemorySaver`): it must be answered in the same run.
66
+ - The gate machinery has no automated coverage; see [trying the gate semantics](skills-and-gates.md#trying-the-gate-semantics).
67
+ - Jobs live in memory: there is no resuming a job after pi exits. The work itself is on disk, so a killed job leaves a partial build rather than nothing.