@turri-dev/cli 0.1.4-next.318a98a → 0.1.4-next.4342332

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 (100) hide show
  1. package/.pi/themes/turri-dark.json +67 -66
  2. package/.pi/themes/turri-light.json +71 -73
  3. package/README.md +39 -127
  4. package/assets/jellyfish/dark-00.png +0 -0
  5. package/assets/jellyfish/dark-01.png +0 -0
  6. package/assets/jellyfish/dark-02.png +0 -0
  7. package/assets/jellyfish/dark-03.png +0 -0
  8. package/assets/jellyfish/dark-04.png +0 -0
  9. package/assets/jellyfish/dark-05.png +0 -0
  10. package/assets/jellyfish/dark-06.png +0 -0
  11. package/assets/jellyfish/dark-07.png +0 -0
  12. package/assets/jellyfish/dark-08.png +0 -0
  13. package/assets/jellyfish/dark-09.png +0 -0
  14. package/assets/jellyfish/dark-10.png +0 -0
  15. package/assets/jellyfish/dark-11.png +0 -0
  16. package/assets/jellyfish/dark-12.png +0 -0
  17. package/assets/jellyfish/dark-13.png +0 -0
  18. package/assets/jellyfish/dark-14.png +0 -0
  19. package/assets/jellyfish/light-00.png +0 -0
  20. package/assets/jellyfish/light-01.png +0 -0
  21. package/assets/jellyfish/light-02.png +0 -0
  22. package/assets/jellyfish/light-03.png +0 -0
  23. package/assets/jellyfish/light-04.png +0 -0
  24. package/assets/jellyfish/light-05.png +0 -0
  25. package/assets/jellyfish/light-06.png +0 -0
  26. package/assets/jellyfish/light-07.png +0 -0
  27. package/assets/jellyfish/light-08.png +0 -0
  28. package/assets/jellyfish/light-09.png +0 -0
  29. package/assets/jellyfish/light-10.png +0 -0
  30. package/assets/jellyfish/light-11.png +0 -0
  31. package/assets/jellyfish/light-12.png +0 -0
  32. package/assets/jellyfish/light-13.png +0 -0
  33. package/assets/jellyfish/light-14.png +0 -0
  34. package/dist/ask.js +34 -15
  35. package/dist/brand.js +7 -7
  36. package/dist/cli-options.js +12 -6
  37. package/dist/config-edit.js +1 -0
  38. package/dist/config.js +5 -2
  39. package/dist/cultivate-cli.js +16 -23
  40. package/dist/extension.js +41 -29
  41. package/dist/init-config.js +5 -0
  42. package/dist/loop-cli.js +19 -7
  43. package/dist/loop-tools.js +11 -5
  44. package/dist/module-report.js +5 -4
  45. package/dist/pi.js +76 -19
  46. package/dist/question-dialog.js +1 -0
  47. package/dist/regenerate/activity.js +21 -0
  48. package/dist/regenerate/list-arguments.js +121 -0
  49. package/dist/regenerate/loop.js +21 -8
  50. package/dist/regenerate/plain-palette.js +51 -36
  51. package/dist/regenerate/regenerate.js +4 -2
  52. package/dist/regenerate/self-check.js +13 -6
  53. package/dist/regenerate/side-panel.js +1 -1
  54. package/dist/regenerate/spec-map-view.js +9 -5
  55. package/dist/regenerate/test-scripts.js +54 -10
  56. package/dist/regenerate/unit-review.js +1 -1
  57. package/dist/regenerate-cli.js +11 -5
  58. package/dist/release-cli.js +3 -8
  59. package/dist/review/live.js +2 -1
  60. package/dist/run-report.js +39 -1
  61. package/dist/validate-cli.js +3 -8
  62. package/docs/README.md +5 -12
  63. package/docs/authoring-plain.md +37 -119
  64. package/docs/config.md +53 -178
  65. package/docs/deploy.md +21 -80
  66. package/docs/development.md +13 -41
  67. package/docs/headless.md +45 -121
  68. package/docs/images/how-turri-works.svg +29 -31
  69. package/docs/installation.md +13 -40
  70. package/docs/parser.md +15 -43
  71. package/docs/regenerating.md +229 -938
  72. package/docs/sandbox.md +38 -152
  73. package/docs/skills-and-gates.md +50 -171
  74. package/docs/theming.md +45 -46
  75. package/docs/using.md +69 -345
  76. package/genome/rules/bullet-continuation.md +5 -13
  77. package/genome/rules/concise-specs-examples.md +2 -4
  78. package/genome/rules/concise-specs-integration-examples.md +2 -6
  79. package/genome/rules/concise-specs.md +1 -2
  80. package/genome/rules/func-specs.md +1 -0
  81. package/genome/rules/integration-embedded-testing.md +1 -4
  82. package/genome/rules/integrations.md +1 -2
  83. package/genome/rules/project-model.md +14 -35
  84. package/genome/rules/stdlib.md +14 -49
  85. package/genome/rules/turri-regeneration.md +48 -0
  86. package/genome/skills/add-implementation-requirement/SKILL.md +1 -2
  87. package/genome/skills/analyze-if-func-spec-too-complex/SKILL.md +3 -8
  88. package/genome/skills/brood/SKILL.md +37 -127
  89. package/genome/skills/brood/references/intent.md +4 -12
  90. package/genome/skills/brood/references/product.md +24 -76
  91. package/genome/skills/brood/references/stack.md +7 -29
  92. package/genome/skills/brood/references/testing.md +11 -42
  93. package/genome/skills/bud/SKILL.md +32 -109
  94. package/genome/skills/bud/references/intent.md +4 -11
  95. package/genome/skills/implement-conformance-testing-script/SKILL.md +3 -6
  96. package/genome/skills/implement-unit-testing-script/SKILL.md +1 -2
  97. package/genome/skills/mature/SKILL.md +21 -69
  98. package/genome/skills/refactor-module/SKILL.md +24 -2
  99. package/genome/skills/spawn/SKILL.md +28 -113
  100. 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,79 +13,42 @@ 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
  | --- | --- |
85
43
  | now | `harness-model` and `models.chat` - the conversation switches to it; `parallel-jobs` - a pulse waiting for a slot starts if there is one now; `allow-to-stop-jobs` |
86
44
  | your next message | `rules-off` - for the conversation; a skill's agents from the next skill run |
87
- | the next pulse - one running keeps what it started with | `coding-model`, `judge-model`, every other `models.<role>`, `review`, `turn-limit`, `compact-at`, `agent-env`, `toolchains` |
45
+ | the next pulse - one running keeps what it started with | `coding-model`, `judge-model`, every other `models.<role>`, `review`, `mutation-testing`, `turn-limit`, `compact-at`, `agent-env`, `toolchains` |
88
46
  | the next time the work is planned | `conformance-tests`, `conformance-budget`, `max-specs-per-pulse`, `max-lines-per-pulse` |
89
47
  | the next test run - the running pulse's too | the testing scripts, `testing-scripts-run-on` |
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
 
@@ -128,6 +83,7 @@ models: # each agent role's model, thinking and tur
128
83
  | `conformance-tests` | `all` (or `true`): conformance tests for every functional spec of every module with test reqs, written once each module's code is built, before anything is built on it. `chosen`: for the functional specs chosen - every one with acceptance tests, and those the chooser picks as each code pulse ends, from what that pulse regenerated. `module`: the same, but the chooser is asked once, when the whole module is regenerated, and plans the conformance pulses too. Under both, the choice is made inside the pulse, before anything is built on the module, and the pulse's report says what was chosen and why; those the person asks for with `conform` are written too; once chosen, a functional spec keeps them, and they are rewritten when it changes - see [who chooses, and when](regenerating.md#conformance-tests-in-the-work-loop). `false`: none written, and none of the existing ones run - until the conversation asks with `conform` | `false` |
129
84
  | `conformance-budget` | under `conformance-tests: chosen` or `module`: how many of a module's functional specs may be chosen for conformance tests, beside those with acceptance tests - a count (`2`) or a share of its functional specs (`30%`, rounded up, at least one). Every choice for the module counts, whenever it was made; the chooser is told what is left, and can choose no more. Your own `conform` is not limited. A stack's `config.turri.<stack>.yaml` can set its own | no limit |
130
85
  | `review` | `true` or `false`: whether the code and its unit tests - and the conformance tests - are reviewed once they pass: two reviews at most, the second weighed by the arbiter; off, a job lands once its tests pass - see [regenerating the code](regenerating.md#the-code-and-its-unit-tests-are-reviewed) | `false` |
86
+ | `mutation-testing` | `true` or `false`: whether the coding agent and the reviewer have `can_it_fail` - one change put in the code for one run of the unit testing script, to see that a test catches it; on a copy of the code, or in place and put back after the run (see [regenerating the code](regenerating.md#checking-its-own-work)). `turri regenerate --mutation-testing false` for one run | `true` |
131
87
  | `rules-off` | a list of rule names - `integrations`, `concise-specs`, the files of `genome/rules/` without `.md` - left out of the conversation's prompt and every spec-writing agent's: a rule this project's own skills or AGENTS.md replace, such as one that says to probe a live API before any spec is written. The project's alone | none |
132
88
  | `allow-to-stop-jobs` | `true` or `false`: whether turri stops a running job the spec has moved on from - a functional spec it regenerates changed, or a file one links was edited - rolls it back and regenerates the spec as it now is. `false`: the job runs to its end and lands, and what changed since is regenerated on top of it by the next job - see [regenerating the code](regenerating.md). Your own `halt` stops a job either way | `true` |
133
89
  | `release-after-pulse` | `true` or `false`: whether every pulse that lands code releases it, in the chat, as its last stage - before the module's next pulse starts, whatever the chat is doing: an agent on the coding model looks for the project's release guidance as the chat does (what was passed to `release` this conversation, AGENTS.md, the project's skills) and, when it says to release after a build, does what it says - see [deploy](deploy.md#after-every-pulse). One release a pulse that lands; a release that fails is said in the pulse's report, and what it landed stays | `false` |
@@ -142,17 +98,13 @@ models: # each agent role's model, thinking and tur
142
98
  | `toolchains` | folders of this machine an agent's commands may read beside the system's, the `PATH`'s and those the toolchain variables point at - a toolchain installed somewhere unusual (`[/srv/zig]`). A stack's add to the project's. See [the OS sandbox](sandbox.md#the-os-sandbox) | none |
143
99
  | `turn-limit` | seconds each turn of an agent a job starts has, for every role without its own (`models:`); `0` for none. The config is the only place it is set. A turn past it ends at its next request to the model - see [regenerating the code](regenerating.md) | 120 |
144
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` |
145
- | `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; it gives the coding agent `can_it_fail` (see [the testing scripts](regenerating.md#the-testing-scripts)) | `in-place` |
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` |
146
102
 
147
- Keys are written with dashes; underscores are read the same (`conformance_tests`). A key turri
148
- 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
149
- wrong type, as if it were not there. `model:`, from before there were separate models, is read as
150
- `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`.
151
104
 
152
105
  ## Models per role
153
106
 
154
- `models:` gives each kind of agent its own model, thinking level and turn limit. Each entry is a model
155
- (`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:
156
108
 
157
109
  | role | the agents |
158
110
  | --- | --- |
@@ -170,37 +122,21 @@ wrong type, as if it were not there. `model:`, from before there were separate m
170
122
  | `arbiter` | the arbiters that weigh a second review |
171
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` |
172
124
 
173
- What an entry leaves out it takes from `default`: `reviewer: { thinking: low }` runs the default model, thinking
174
- 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
175
- `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.
176
126
 
177
- A role whose thinking nothing names - neither its entry, `default`'s, nor a `:level` on the model it runs on - thinks
178
- as its kind of work needs: **low** for the agents that do the work (`coding`, `conformance`, `explorer`, `release`),
179
- which work from specs that leave little to guess and take many turns, and **medium** for the ones that judge
180
- (`reviewer`, `test-reviewer`, `judge`, `arbiter`, `debugger`, `planner`, `chooser`, `diagnosis`), where a wrong
181
- call costs pulses. A judging role that falls back on the coding model takes its model alone, not its thinking. The
182
- 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.
183
128
 
184
- The thinking level reaches the model as each provider takes it. OpenAI's models on Bedrock are sent it as their
185
- 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.
186
130
 
187
131
  ## How many jobs at once
188
132
 
189
- Jobs on the same module, or on modules of one `requires` chain, always run one after another.
190
- Modules that share nothing - a backend, a frontend, a worker, ten of them - build side by side, each
191
- pulse's builds and tests running on this machine beside your own work. So the chat runs at most `parallel-jobs` jobs
192
- 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
193
- 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,
194
- 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.
195
134
 
196
- The testing scripts all run on this machine, each on a copy of its module's code, so they never
197
- share files - but they do share its network: two modules whose conformance scripts start a server
198
- 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.
199
136
 
200
137
  ## Models
201
138
 
202
- Each model is a model reference and a thinking level - `off`, `minimal`, `low`, `medium`, `high`,
203
- `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:
204
140
 
205
141
  ```yaml
206
142
  coding-model:
@@ -210,9 +146,7 @@ judge-model: google/gemini-3.1-pro:high # the same, as one string
210
146
  harness-model: anthropic/claude-opus-5-5 # a model alone
211
147
  ```
212
148
 
213
- What a model leaves out it takes from the one it inherits: `judge-model` from `coding-model` - its model, not its
214
- 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;
215
- `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.
216
150
 
217
151
  They are defaults. What is asked for wins over them:
218
152
 
@@ -222,52 +156,31 @@ They are defaults. What is asked for wins over them:
222
156
  | coding | `turri --coding-model <m>`, `engine` in the conversation |
223
157
  | judge | - |
224
158
 
225
- `turri regenerate`, `conform` and `spec-diff` read `--harness-model`, `--coding-model` (or `--model`),
226
- `--judge-model`, `--review` and `--conformance-tests` differently: as the keys themselves, as if the file had
227
- them. Each takes its key's value and its place in the order above - a `models:` entry still wins over it - so a
228
- 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.
229
160
 
230
161
  A job keeps the model it was queued with: choosing another holds for what is queued after.
231
162
 
232
163
  ## Conformance tests
233
164
 
234
- `conformance-tests:` is the one switch, and the chat, every render and `brood`'s testing phase
235
- follow it. `false` turns them off entirely: no conformance tests are written, the ones already in a
236
- codebase are not run, and no agent is shown the conformance testing script. No key is the same as
237
- `false`: conformance tests are off by default. `all` (or `true`) means on wherever a module has
238
- `***test reqs***` - a module without them has nothing to write conformance tests from, so it writes
239
- none, but still keeps the codebase's existing ones passing. Asked in the
240
- conversation (`conform`), or with `--conformance-tests all|chosen|module|false` on `turri regenerate` and
241
- `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.
242
166
 
243
- `spawn` writes `conformance-tests: false` into a new project unless you ask for tests;
244
- `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.
245
168
 
246
169
  ## The testing scripts
247
170
 
248
- A build needs a unit testing script - and, with conformance on, a conformance testing script - to
249
- 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:
250
172
 
251
173
  1. named in the config - the chosen stack's file first, then `config.turri.yaml` - by path from the root;
252
174
  2. the one `run_unittests*.sh` / `run_conformance_tests*.sh` in the project root;
253
175
  3. the one of each in `test_scripts/`.
254
176
 
255
- The optional prepare script - `prepare-environment-script:`, else the one `prepare_environment*.sh` - is looked for the
256
- 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.
257
178
 
258
- A folder holding two of a kind is not guessed between: name the one to use. A script named inside
259
- `plain_modules/` is refused - agents write there, so it could be changed by the work it judges. The
260
- scripts are never linked from the specs. What they are and how they run is in
261
- [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).
262
180
 
263
181
  ## Credentials for the agents
264
182
 
265
- An agent's commands do not get the environment turri was started in: it holds your providers' API keys, cloud
266
- credentials and tokens. They get only the path, the locale, the terminal and the user, the variables that locate your
267
- toolchains (`JAVA_HOME`, `NVM_DIR`, `RUSTUP_HOME`, ... - the ones in your home found even when your shell sets none),
268
- and turri's own: a home folder of the module's own (`plain_modules/.turri/home/<module>`, kept between pulses, with a
269
- git identity of its own), a `TMPDIR`, the package caches in `plain_modules/.turri/cache`, and git stopped at the module
270
- 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.
271
184
 
272
185
  A project whose agents need a credential while they work names it:
273
186
 
@@ -277,24 +190,13 @@ agent-env:
277
190
  vars: [D365_TENANT_ID] # these variables, from the environment turri was started in
278
191
  ```
279
192
 
280
- What it names reaches every agent with a shell, as environment variables of its commands only - the file stays where
281
- it is, outside every agent's reach - and never replaces turri's own home, `TMPDIR` or caches. A stack's file adds
282
- to the project's. A file that is not there, or a variable unset or empty, is reported as missing. The testing scripts
283
- 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.
284
194
 
285
- Their values never appear in what an agent is shown or what turri writes: each is replaced by its name -
286
- `[D365_CLIENT_SECRET]` - whole, URL-encoded, or split over a command's output as it streams: in every tool result and
287
- refusal an agent is given (and so in the session transcripts, which hold only those), in the whole outputs kept for
288
- `read_output`, and in the job and debug logs. A value shorter than four characters is not masked - `1` or `eu` is
289
- 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.
290
196
 
291
197
  ## Stacks
292
198
 
293
- One project can hold parts that share nothing but a common module - a Python backend and a React
294
- frontend side by side, each importing `base` from `template/`, neither requiring the other - each
295
- needing its own testing scripts. Each stack gets a file of its own beside `config.turri.yaml`,
296
- `config.turri.<stack>.yaml`, holding what differs for it - typically its testing scripts, its
297
- `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:
298
200
 
299
201
  ```
300
202
  config.turri.yaml # the project's: harness-model, coding-model, conformance-tests
@@ -316,50 +218,23 @@ coding-model:
316
218
 
317
219
  A stack is chosen, never worked out from the spec:
318
220
 
319
- - **In the chat**, with `/stack` - a list of the project's stacks and none - or `/stack backend`, `/stack none`.
320
- 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
321
- stack builds. `/stack` alone says which is chosen now.
322
- - **On the command line**, with `--stack <name>` on any command - `turri regenerate`, `conform`, `spec-diff`, `glimpse`,
323
- `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.
324
223
 
325
- The choice lasts for the session only: nothing remembers it, and turri started again has none chosen. A stack the
326
- 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.
327
225
 
328
226
  How a stack's config is made:
329
227
 
330
- - **Laid over `config.turri.yaml`, key by key.** What the stack's file gives wins; what it leaves out
331
- is the project's. A model it names takes what it leaves out from the project's same model - above,
332
- with the stack frontend chosen, everything renders on the project's coding model, thinking `high`.
333
- - **For everything built while it is chosen.** Every pulse that starts, every test run and every
334
- script found from then on is the chosen stack's; a pulse already running keeps the stack it
335
- started with. Choose the stack before building the part it is for: `/stack backend`, then
336
- `regenerate backend.plain`.
337
- - **The project's alone.** `module:`, `harness-model:`, `parallel-jobs:`, `rules-off:` and `compact-at:` are read
338
- only from `config.turri.yaml` - there is one conversation, one module built when none is named, one machine.
339
- `agent-env:` and `toolchains:` in a stack's file add to the project's.
340
-
341
- The chat is told each stack's config and the one chosen. The skills that write testing scripts put
342
- each stack's in its own file once a project has two stacks, and say which stack to choose before
343
- 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.
344
233
 
345
234
  ## The old config.yaml
346
235
 
347
- turri's settings were once in `config.yaml`, and a stack's in `config.<stack>.yaml`. A `config.yaml`
348
- may be another tool's, so turri never writes one. While a project folder has no `config.turri*.yaml`
349
- at all, turri still reads its `config.yaml`, and each `config.<name>.yaml` as the stack `<name>`.
350
-
351
- The first time turri itself writes a setting there with `/turri-config`, it copies `config.yaml` to
352
- `config.turri.yaml` and each `config.<name>.yaml` to `config.turri.<name>.yaml` first, leaves the old
353
- files as they are, and from then on reads only the new ones. `turri init-config` copies the stacks'
354
- files the same way, but writes `config.turri.yaml` as its quick start, taking from `config.yaml` only
355
- the keys turri reads too - `unittests-script`, `conformance-tests-script` and
356
- `prepare-environment-script`, say - each in its place in the file, and saying which keys it left:
357
- `template_dir`, `verbose`, `api`, the other tool's alone. The two models are the vendor's, never taken. To change a
358
- setting by hand in such a project, do the same: copy the files to their new names, and edit the
359
- copies - never `config.yaml`. Writing a `config.turri.yaml` of your own beside it is the same move: from then on
360
- `config.yaml` is not read, its testing scripts with it. For a headless run that only needs conformance tests or
361
- another judge, or review, those options leave the files alone: `--conformance-tests`, `--judge-model`, `--review true|false`, and the models' too.
362
-
363
- Keys turri does not read - another tool's `verbose`, `api-key`, `build-folder`, ... - are ignored without a word, and so
364
- 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
365
- 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>`.