@turri-dev/cli 0.1.27 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/README.md +6 -6
  2. package/dist/advisor-chat.d.ts +63 -0
  3. package/dist/advisor-chat.js +290 -0
  4. package/dist/background-skills.d.ts +53 -0
  5. package/dist/background-skills.js +121 -0
  6. package/dist/bedrock-region.d.ts +66 -0
  7. package/dist/bedrock-region.js +144 -0
  8. package/dist/btw.d.ts +1 -1
  9. package/dist/btw.js +1 -1
  10. package/dist/change-plain-cli.js +20 -13
  11. package/dist/chat-idle.d.ts +7 -0
  12. package/dist/chat-idle.js +20 -0
  13. package/dist/chats.d.ts +10 -0
  14. package/dist/chats.js +23 -0
  15. package/dist/cli-options.d.ts +1 -2
  16. package/dist/cli-options.js +2 -7
  17. package/dist/cli.js +11 -3
  18. package/dist/config-command.d.ts +14 -0
  19. package/dist/config-command.js +35 -15
  20. package/dist/config-edit.d.ts +3 -3
  21. package/dist/config-edit.js +16 -12
  22. package/dist/config.d.ts +54 -34
  23. package/dist/config.js +40 -44
  24. package/dist/conform-cli.js +12 -10
  25. package/dist/conformance-switch.d.ts +34 -0
  26. package/dist/conformance-switch.js +108 -0
  27. package/dist/cultivate-cli.js +15 -5
  28. package/dist/drift-cli.js +2 -0
  29. package/dist/extension.d.ts +15 -0
  30. package/dist/extension.js +260 -83
  31. package/dist/host-session.d.ts +26 -0
  32. package/dist/host-session.js +30 -2
  33. package/dist/host.d.ts +5 -2
  34. package/dist/host.js +7 -1
  35. package/dist/init-config.d.ts +1 -1
  36. package/dist/init-config.js +20 -11
  37. package/dist/loop-cli.d.ts +3 -3
  38. package/dist/loop-cli.js +13 -16
  39. package/dist/loop-tools.js +18 -10
  40. package/dist/model-check.d.ts +8 -3
  41. package/dist/model-check.js +13 -8
  42. package/dist/new-project.js +12 -8
  43. package/dist/{validate-cli.js → parse-cli.js} +11 -5
  44. package/dist/parse-tool.d.ts +9 -0
  45. package/dist/parse-tool.js +33 -0
  46. package/dist/pi-launch.js +1 -1
  47. package/dist/plain/check.d.ts +53 -6
  48. package/dist/plain/check.js +217 -24
  49. package/dist/plain/concepts.d.ts +8 -0
  50. package/dist/plain/concepts.js +66 -23
  51. package/dist/plain/cycles.d.ts +21 -0
  52. package/dist/plain/cycles.js +190 -0
  53. package/dist/plain/errors.d.ts +4 -0
  54. package/dist/plain/errors.js +7 -0
  55. package/dist/plain/files.d.ts +18 -1
  56. package/dist/plain/files.js +39 -2
  57. package/dist/plain/graph.d.ts +33 -4
  58. package/dist/plain/graph.js +60 -12
  59. package/dist/plain/highlight.d.ts +3 -2
  60. package/dist/plain/highlight.js +4 -3
  61. package/dist/plain/index.d.ts +8 -5
  62. package/dist/plain/index.js +8 -5
  63. package/dist/plain/liquid.js +1 -6
  64. package/dist/plain/markdown.d.ts +32 -3
  65. package/dist/plain/markdown.js +146 -24
  66. package/dist/plain/module-concepts.js +2 -2
  67. package/dist/plain/parser.d.ts +83 -28
  68. package/dist/plain/parser.js +381 -260
  69. package/dist/plain/plain.tmLanguage.json +29 -3
  70. package/dist/plain/project.d.ts +48 -0
  71. package/dist/plain/project.js +155 -0
  72. package/dist/plain/spec.d.ts +90 -28
  73. package/dist/plain/spec.js +107 -133
  74. package/dist/plain/test-plain-file.d.ts +59 -0
  75. package/dist/plain/test-plain-file.js +232 -0
  76. package/dist/regenerate/activity.d.ts +20 -9
  77. package/dist/regenerate/activity.js +11 -4
  78. package/dist/regenerate/advisor-records.d.ts +93 -0
  79. package/dist/regenerate/advisor-records.js +110 -0
  80. package/dist/regenerate/advisor-runs.d.ts +87 -0
  81. package/dist/regenerate/advisor-runs.js +327 -0
  82. package/dist/regenerate/base-folder.d.ts +68 -0
  83. package/dist/regenerate/base-folder.js +168 -0
  84. package/dist/regenerate/cases.d.ts +9 -6
  85. package/dist/regenerate/cases.js +70 -14
  86. package/dist/regenerate/change-view.d.ts +8 -3
  87. package/dist/regenerate/change-view.js +71 -22
  88. package/dist/regenerate/chunk-plan.d.ts +36 -15
  89. package/dist/regenerate/chunk-plan.js +165 -59
  90. package/dist/regenerate/conform.d.ts +3 -0
  91. package/dist/regenerate/conform.js +6 -5
  92. package/dist/regenerate/conformance-agents.d.ts +18 -39
  93. package/dist/regenerate/conformance-agents.js +60 -88
  94. package/dist/regenerate/conformance.d.ts +23 -13
  95. package/dist/regenerate/conformance.js +119 -82
  96. package/dist/regenerate/diff-view.d.ts +1 -1
  97. package/dist/regenerate/diff-view.js +20 -4
  98. package/dist/regenerate/drift.d.ts +47 -15
  99. package/dist/regenerate/drift.js +101 -30
  100. package/dist/regenerate/jobs.d.ts +2 -2
  101. package/dist/regenerate/jobs.js +1 -1
  102. package/dist/regenerate/ledger.d.ts +19 -0
  103. package/dist/regenerate/loop.d.ts +62 -43
  104. package/dist/regenerate/loop.js +472 -341
  105. package/dist/regenerate/paths.d.ts +4 -0
  106. package/dist/regenerate/paths.js +7 -1
  107. package/dist/regenerate/plain-palette.js +2 -0
  108. package/dist/regenerate/prompt.d.ts +57 -19
  109. package/dist/regenerate/prompt.js +157 -122
  110. package/dist/regenerate/records.d.ts +43 -12
  111. package/dist/regenerate/records.js +102 -88
  112. package/dist/regenerate/regenerate.js +29 -11
  113. package/dist/regenerate/regression.d.ts +4 -4
  114. package/dist/regenerate/regression.js +14 -10
  115. package/dist/regenerate/renames.d.ts +42 -0
  116. package/dist/regenerate/renames.js +185 -0
  117. package/dist/regenerate/requires.d.ts +1 -1
  118. package/dist/regenerate/requires.js +10 -3
  119. package/dist/regenerate/resources.d.ts +5 -3
  120. package/dist/regenerate/resources.js +4 -4
  121. package/dist/regenerate/scripts-being-written.d.ts +19 -0
  122. package/dist/regenerate/scripts-being-written.js +30 -0
  123. package/dist/regenerate/spec-map-view.d.ts +2 -2
  124. package/dist/regenerate/spec-map-view.js +46 -15
  125. package/dist/regenerate/spec-map.d.ts +27 -5
  126. package/dist/regenerate/spec-map.js +92 -60
  127. package/dist/regenerate/spec-steps.d.ts +48 -5
  128. package/dist/regenerate/spec-steps.js +213 -28
  129. package/dist/regenerate/state.d.ts +4 -3
  130. package/dist/regenerate/stop-report.d.ts +1 -1
  131. package/dist/regenerate/stop-report.js +10 -10
  132. package/dist/regenerate/test-advisor.d.ts +101 -0
  133. package/dist/regenerate/test-advisor.js +379 -0
  134. package/dist/regenerate/test-kinds.d.ts +71 -28
  135. package/dist/regenerate/test-kinds.js +110 -63
  136. package/dist/regenerate/test-scripts.d.ts +2 -0
  137. package/dist/regenerate/test-scripts.js +4 -0
  138. package/dist/regenerate/testing-steps.d.ts +41 -0
  139. package/dist/regenerate/testing-steps.js +110 -0
  140. package/dist/regenerate/testing.d.ts +1 -1
  141. package/dist/regenerate/testing.js +5 -4
  142. package/dist/regenerate/unit-review.d.ts +1 -1
  143. package/dist/regenerate/unit-review.js +3 -3
  144. package/dist/regenerate-cli.js +11 -12
  145. package/dist/release-agent.js +4 -0
  146. package/dist/release-cli.js +2 -0
  147. package/dist/release-tools.js +2 -0
  148. package/dist/run-report.d.ts +2 -2
  149. package/dist/run-report.js +4 -3
  150. package/dist/self-invocation.d.ts +1 -1
  151. package/dist/self-invocation.js +1 -1
  152. package/dist/sentinel.js +1 -1
  153. package/dist/setup.d.ts +10 -0
  154. package/dist/setup.js +52 -4
  155. package/dist/skill.d.ts +10 -0
  156. package/dist/skill.js +6 -0
  157. package/dist/skills.js +3 -1
  158. package/dist/spec-tools.js +21 -31
  159. package/dist/test-plain-files.d.ts +41 -0
  160. package/dist/test-plain-files.js +177 -0
  161. package/docs/README.md +3 -1
  162. package/docs/authoring-plain.md +46 -13
  163. package/docs/chats.md +3 -1
  164. package/docs/config.md +20 -15
  165. package/docs/deploy.md +1 -1
  166. package/docs/development.md +2 -1
  167. package/docs/headless.md +15 -18
  168. package/docs/hosting.md +28 -12
  169. package/docs/installation.md +1 -0
  170. package/docs/parser.md +88 -27
  171. package/docs/regenerating.md +87 -52
  172. package/docs/sentinel.md +1 -1
  173. package/docs/skills-and-gates.md +3 -1
  174. package/docs/test-advisor.md +110 -0
  175. package/docs/theming.md +1 -1
  176. package/docs/using.md +17 -15
  177. package/genome/rules/bullet-continuation.md +8 -8
  178. package/genome/rules/concise-specs-examples.md +111 -80
  179. package/genome/rules/concise-specs-integration-examples.md +56 -41
  180. package/genome/rules/concise-specs.md +17 -16
  181. package/genome/rules/definitions.md +5 -5
  182. package/genome/rules/examples/integration-embedded-testing/run_conformance_tests_java.sh +1 -1
  183. package/genome/rules/func-specs.md +69 -74
  184. package/genome/rules/impl-reqs.md +4 -4
  185. package/genome/rules/integration-embedded-testing.md +20 -20
  186. package/genome/rules/integration-embedded.md +31 -31
  187. package/genome/rules/integration-standalone.md +9 -9
  188. package/genome/rules/integrations.md +18 -18
  189. package/genome/rules/linked-resources.md +19 -16
  190. package/genome/rules/module-structure.md +21 -14
  191. package/genome/rules/project-model.md +18 -17
  192. package/genome/rules/required-concepts.md +1 -1
  193. package/genome/rules/requires-modules.md +6 -5
  194. package/genome/rules/semantic-ids.md +49 -0
  195. package/genome/rules/stdlib.md +4 -5
  196. package/genome/rules/test-plain-files.md +130 -0
  197. package/genome/rules/test-reqs.md +8 -8
  198. package/genome/rules/turri-regeneration.md +23 -8
  199. package/genome/skills/analyze-2-func-specs/SKILL.md +36 -21
  200. package/genome/skills/analyze-func-specs/SKILL.md +46 -32
  201. package/genome/skills/break-down-func-spec/SKILL.md +91 -67
  202. package/genome/skills/consolidate-concepts/SKILL.md +10 -10
  203. package/genome/skills/convert-old-syntax/SKILL.md +68 -0
  204. package/genome/skills/convert-old-syntax/references/rubric.md +11 -0
  205. package/genome/skills/debug-specs/SKILL.md +62 -56
  206. package/genome/skills/implement-conformance-testing-script/SKILL.md +19 -15
  207. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +2 -2
  208. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +2 -2
  209. package/genome/skills/implement-unit-testing-script/SKILL.md +14 -10
  210. package/genome/skills/refactor-module/SKILL.md +35 -35
  211. package/genome/skills/resolve-section-ownership/SKILL.md +9 -9
  212. package/genome/skills/resolve-spec-conflict/SKILL.md +35 -29
  213. package/package.json +7 -6
  214. package/dist/regenerate/choose-conformance.d.ts +0 -32
  215. package/dist/regenerate/choose-conformance.js +0 -117
  216. /package/dist/{validate-cli.d.ts → parse-cli.d.ts} +0 -0
@@ -11,6 +11,7 @@ my-project/
11
11
  app.plain # a root module: what the software does
12
12
  users.plain # another module, perhaps one that `requires` app
13
13
  template/ # import modules: shared definitions and reqs
14
+ tests/ # test plain files: tests/<module>/<func-id>.plain, one a functional spec
14
15
  resources/ # files specs link to: schemas, API specs, sample data
15
16
  test_scripts/ # scripts that run the unit and conformance tests
16
17
  plain_modules/ # generated - code, tests, history; never edited by hand
@@ -25,9 +26,9 @@ A `.plain` file is one module: optional YAML frontmatter, then up to four sectio
25
26
  | `***definitions***` | the concepts, written `:CamelCase:` - every concept is defined before it is used | `- :Task: is a unit of work with a title and a due date.` |
26
27
  | `***implementation reqs***` | HOW it is built: stack, architecture, coding standards, and everything about unit tests | `- :Implementation: is written in Python 3.12.` |
27
28
  | `***test reqs***` | everything about the black-box conformance tests: framework, how they run, mocking | `- :ConformanceTests: use pytest and call the CLI as a subprocess.` |
28
- | `***functional specs***` | WHAT it does - observable, language-agnostic behaviour, one functionality per item, in the order they are built | `- A :User: can add a :Task:.` |
29
+ | `***functional specs***` | WHAT it does - observable, language-agnostic behaviour, one functionality under each `# <func-id>` heading, in the order they are built | `# add-task` over `A :User: can add a :Task:.` |
29
30
 
30
- Under a functional spec, a nested `***acceptance tests***` list states how that one functionality is checked end to end.
31
+ A functional spec is a `# <func-id>` heading - lowercase letters and digits in words joined by `-`, unique in its module - and its text under it, as free markdown: paragraphs, lists, code blocks. Its scenarios, when it has any, are in its test plain file, `tests/<module>/<func-id>.plain` (the folder is `test-dir`), with `module:` and `func_id:` in its frontmatter, then `***conformance tests***` and `***acceptance tests***`, each scenario a `# <scenario-id>` heading and its text - a section only when it has a scenario: an empty one is a syntax error. A functional spec with no scenarios has no test plain file, and is not tested; an empty test plain file is a syntax error too. People and turri name a functional spec `<module>:<func-id>` - `todo:add-task`.
31
32
 
32
33
  The frontmatter connects modules:
33
34
 
@@ -43,6 +44,35 @@ Beyond that: \*\*\*plain links to files under `resources/` with markdown link sy
43
44
 
44
45
  **Section ownership is the rule that bites.** turri reads each kind of fact only from the section that owns it. A tech choice written into a functional spec, or a behaviour written into the implementation reqs, is not flagged - it is simply not read.
45
46
 
47
+ ## Tests, when they are asked for
48
+
49
+ A test plain file holds the scenarios of one functional spec: `***conformance tests***` for its expected use - the main path, with valid input and the data there - and `***acceptance tests***` for the use that is not expected - invalid input, missing authentication, missing data. Scenarios alone decide what is tested: the conformance agent writes at least one test for each, labelled with its scenario-id, and none of its own.
50
+
51
+ ```plain
52
+ ---
53
+ module: todo
54
+ func_id: add-task
55
+ ---
56
+
57
+ ***conformance tests***
58
+
59
+ # add-valid-task
60
+ Adding a :Task: named "Buy milk" to an empty :TaskList: shows one :Task: named "Buy milk".
61
+
62
+ ***acceptance tests***
63
+
64
+ # reject-short-name
65
+ Adding a :Task: named "Go" is rejected with the error "Name must be at least 3 characters".
66
+ ```
67
+
68
+ Nothing about testing is written until the person asks for it, or the [test advisor](test-advisor.md) finds a functional spec that needs it: a module imports its stack alone, and a new functional spec gets no test plain file. The first time tests are written in a module, turri does three things, in this order, each a change the person sees:
69
+
70
+ 1. **The test reqs** - the stack's conformance template, `stdlib/<kind>/conformance/<stack>`, or the module's own `***test reqs***` when it has no stack from the standard library.
71
+ 2. **The conformance testing script** - with `implement-conformance-testing-script`, when the project has none for the module's stack. It runs in the background on the module's coding model; the conformance tests wait for it.
72
+ 3. **The scenarios** - for the functional specs the person named, conformance scenarios and, only when asked for, acceptance scenarios, written with `change_plain` with no further confirmation. Scenarios in one functional spec say nothing about another: the rest stay untested until they are asked for too.
73
+
74
+ Scenarios that exist are kept in step with their functional specs: a functional spec changed has its scenarios reviewed in the same \*\*\*plain diff, and one split, moved, renamed or taken out takes its test plain file with it. The rules are in `test-plain-files.md`.
75
+
46
76
  ## The standard library
47
77
 
48
78
  turri ships a standard library of import modules in `stdlib/` that settle everything about a generic piece of software on one stack except what it does: its language and framework, layout, configuration, error handling, logging, shutdown, and how it is unit and conformance tested. A module's \*\*\*plain imports one and writes only its own concepts and functional specs:
@@ -51,12 +81,12 @@ turri ships a standard library of import modules in `stdlib/` that settle everyt
51
81
  ---
52
82
  import:
53
83
  - stdlib/backend/python-flask
54
- - stdlib/backend/conformance/python-flask # leave it out to skip conformance tests
55
84
  ---
56
85
 
57
86
  ***functional specs***
58
87
 
59
- - ...
88
+ # <func-id>
89
+ ...
60
90
  ```
61
91
 
62
92
  | kind | stacks - each with `stdlib/<kind>/conformance/<stack>` beside it |
@@ -82,12 +112,12 @@ It is built in three layers, and a stack imports the other two:
82
112
 
83
113
  Each conformance template imports its kind's `conformance/common`: a backend's tests start the built service on a free port and reach it over HTTP only, checking a failure by status and `error.code`; a frontend's run the served build in Chromium through Playwright with the backend stood in; a command-line tool's run the built tool as a process; a library's go through its public entry point.
84
114
 
85
- - **Conformance tests apart.** \*\*\*plain without the conformance template has no test reqs, so no conformance tests are written or run for it. Turning them on later is adding that one import.
115
+ - **Conformance tests apart.** A module imports its stack alone. The stack's conformance template is its test reqs: it is imported the first time the person asks for tests in the module, before the conformance testing script and the scenarios (see [tests](#tests-when-they-are-asked-for)).
86
116
  - **A reserved name.** An import that starts with `stdlib/` is always turri's template, never a file of the project's. A project with a module at such a path - `stdlib/backend/python-fastapi.plain` beside the project's \*\*\*plain, in its `template/` folder or in `PLAIN_TEMPLATE_DIRS` - gets an error saying the name is reserved, so which one the project's \*\*\*plain builds on never depends on what is on disk beside it.
87
117
  - **No concepts.** Its requirements are on the predefined `:Implementation:`, `:UnitTests:` and `:ConformanceTests:` only, so it never collides with \*\*\*plain's own definitions.
88
118
  - **Pinned to a toolchain.** It names its stack's toolchain - Python 3.12, Node.js 24, Java 21, Go 1.25, Rust - which the agents use from this machine; `turri doctor` says when the machine lacks it.
89
- - **Not storage, not the testing scripts.** A module with a database says which on top of its stack. It still needs its unit testing script, and a conformance testing script when it has conformance tests.
90
- - **Known to the agents.** The `stdlib` rule, in the system prompt of every agent that writes \*\*\*plain, says when to import which, and lists every template with what it is and the folder it is in, read from `stdlib/` when the rules load. The conversation imports a stack when the one chosen is in it, and its conformance template when conformance tests are on.
119
+ - **Not storage, not the testing scripts.** A module with a database says which on top of its stack. It still needs its unit testing script, and a conformance testing script once its first tests are asked for.
120
+ - **Known to the agents.** The `stdlib` rule, in the system prompt of every agent that writes \*\*\*plain, says when to import which, and lists every template with what it is and the folder it is in, read from `stdlib/` when the rules load. The conversation imports a stack when the one chosen is in it, and its conformance template once the person asks for tests.
91
121
  - **Only what this machine can build.** The agents use this machine's toolchains and install none, so a Go stack on a laptop without Go stops at its first build. Every agent that writes \*\*\*plain, and the conversation, are told which of the standard library's languages the machine can build now - Python needs `uv`, TypeScript and every frontend `node` and `npm`, Go `go`, Rust `cargo`, Java a JDK (`src/stack.ts`, `toolchainsBlock`) - and the conversation offers, and chooses, only stacks in those. A stack the person names in a language the machine lacks is not refused: they are told what to install first, and that `turri doctor` checks it.
92
122
 
93
123
  A requirement beyond the stack - storage, an outside service - is added on top of it. A module that differs from its stack on something the stack settles - another framework, another layout - writes its own instead: an import cannot be taken back in part.
@@ -100,11 +130,13 @@ A requirement beyond the stack - storage, an outside service - is added on top o
100
130
  | --- | --- |
101
131
  | `module-structure.md` | the file skeleton, frontmatter fields, section order, module kinds, section ownership |
102
132
  | `definitions.md` | concept syntax, predefined concepts, define before use, no circular definitions, granularity |
103
- | `func-specs.md` | voice, the complexity limit, chronological order, no conflicts, how a functional spec is added - checked for size and conflicts before it is written in - and where it goes, language agnosticism, testability, acceptance tests |
133
+ | `func-specs.md` | a functional spec's shape - a `# <func-id>` heading and a free-text body - voice, the complexity limit, chronological order, no conflicts, how a functional spec is added - checked for size and conflicts before it is written in, with its test plain file - and where it goes, language agnosticism, testability |
134
+ | `semantic-ids.md` | func-ids and scenario-ids: their syntax, unique in the module or the functional spec, a pure rename cheap and a rename with any other change a functional spec taken out and another added, a functional spec named `<module>:<func-id>` |
135
+ | `test-plain-files.md` | test plain files in `tests/<module>/`, their two sections and their scenarios, keeping them in step with the functional specs, and writing scenarios once the person asks for tests - test reqs, the conformance testing script, then the scenarios |
104
136
  | `impl-reqs.md` | HOW not WHAT, unit tests live here, what belongs and what does not |
105
137
  | `test-reqs.md` | conformance tests only, what belongs, test types |
106
138
  | `concise-specs.md` (+ two example banks) | keeping \*\*\*plain short enough for a person to review: no obvious lines, plain words, no uncheckable adjectives, no hedging |
107
- | `bullet-continuation.md` | bullets and continuation lines in every section |
139
+ | `bullet-continuation.md` | bullets and continuation lines in the definitions, implementation reqs and test reqs |
108
140
  | `linked-resources.md` | a linked resource is one text file on disk, or a PNG or JPEG image for a model that reads images; protocol artifacts are linked, never transcribed |
109
141
  | `import-modules.md`, `requires-modules.md` | the two ways modules build on each other |
110
142
  | `exported-concepts.md`, `required-concepts.md` | which concepts cross module boundaries |
@@ -114,7 +146,7 @@ A requirement beyond the stack - storage, an outside service - is added on top o
114
146
 
115
147
  The ones that shape \*\*\*plain most:
116
148
 
117
- - **One functionality is at most ~200 lines of code.** A bigger one is split before it is written (`break-down-func-spec`) - the author judges its size by the signs in `func-specs.md`.
149
+ - **One functional spec is at most ~200 lines of code.** A bigger one is split before it is written (`break-down-func-spec`) - the author judges its size by the signs in `func-specs.md`.
118
150
  - **Functional specs are in build order.** Each is regenerated on top of the ones before it - which is what a functional spec may assume, not what a change costs: a functional spec inserted anywhere is regenerated alone.
119
151
  - **They state facts, with a concrete subject.** "A :User: can add a :Task:" - not "Implement adding tasks", not "The system should…".
120
152
  - **Nothing a test cannot check.** No `robust`, `seamless`, `as appropriate`; state the checkable fact or cut the word.
@@ -131,10 +163,11 @@ Every skill in `genome/skills/` can be run from a conversation; most are also us
131
163
  | to… | skills |
132
164
  | --- | --- |
133
165
  | start a project | ask, in the conversation: turri writes it itself, with no skill |
134
- | add to \*\*\*plain | ask in the conversation: it writes a concept, a functional spec, a req, an acceptance test or a linked resource itself, by the rules in its prompt, as a \*\*\*plain diff |
166
+ | add to \*\*\*plain | ask in the conversation: it writes a concept, a functional spec - with no test plain file, until you ask for its tests - a req or a linked resource itself, by the rules in its prompt, as a \*\*\*plain diff - and, once you ask for tests, the scenarios (see [tests](#tests-when-they-are-asked-for)) |
135
167
  | check what is written | `analyze-2-func-specs`, `analyze-func-specs`, `resolve-section-ownership` |
136
168
  | fix what is written | `break-down-func-spec`, `resolve-spec-conflict`, `debug-specs` |
137
169
  | restructure modules | `refactor-module`, `consolidate-concepts` |
170
+ | move a module from the old syntax | `convert-old-syntax` - one module at a time, the lowest of its chain first: it proposes the func-ids and scenario-ids, and once the person confirms them writes the module and its test plain files in one \*\*\*plain diff, word for word, then validates it; it regenerates nothing |
138
171
  | set up the project to build | `implement-unit-testing-script`, `implement-conformance-testing-script` |
139
172
 
140
173
  `debug-specs` is the one for a running application that misbehaves: it reads the generated code to find the cause, traces it back to \*\*\*plain, and fixes only the `.plain` files.
@@ -142,9 +175,9 @@ Every skill in `genome/skills/` can be run from a conversation; most are also us
142
175
  ## Checking \*\*\*plain
143
176
 
144
177
  ```bash
145
- turri validate app.plain # or validate in a conversation
178
+ turri parse app.plain # or parse in a conversation
146
179
  ```
147
180
 
148
- It parses \*\*\*plain with this repo's own parser, resolves its imports and required modules, and reports every syntax, concept and structure error with its line - no model, no API key. The interview skills run it before a phase ends, and `change_plain` refuses a change that leaves a file that does not parse. Pass the project directory to check every module at once.
181
+ It parses \*\*\*plain with this repo's own parser - each module with its test plain files - resolves its imports and required modules, and reports every syntax, concept and structure error with its line, and every test plain file outside its module's folder; it lists each functional spec with its scenarios - `no scenarios - not tested` for one without, which is no problem - and warns of a step of adding tests that was skipped. No model, no API key. The interview skills run it before a phase ends, and `change_plain` refuses a change that leaves a file that does not pass. Pass the project directory to check every module at once.
149
182
 
150
183
  What `check` cannot see - a fact in the wrong section, a functional spec that is too big, two that conflict, wording no test can check - is what the rules, the skills and the reviewers are for.
package/docs/chats.md CHANGED
@@ -23,6 +23,8 @@ The session's, shared by every chat:
23
23
 
24
24
  A pulse's end goes to the [sentinel](sentinel.md) - a chat of turri's own, opened in the background with the first pulse that finishes, once you said to start it under `sentinel: ask` - which checks it, tests what was released, and puts what needs you as a notice in the chat you are in. That chat shows the pulse's end; its agent is told of a pulse that landed, to tell you so and what the sentinel is doing with it - and when the sentinel is done with any pulse, what it found - and nothing more - and not of one that went wrong: the sentinel's notice is what it hears of that. With `sentinel: false`, a pulse's end is told to the chat that asked for it instead, shown or not - its agent reacts to it there; the chat's mark in the strip says it has something new. When that chat has been closed, the chat shown is told. Closing a chat stops its turn, never its pulses.
25
25
 
26
+ The session has one [test advisor](test-advisor.md), which checks new and changed functional specs in the background for whether they need testing scenarios. Its verdict goes to the chat you are looking at, once that chat is idle: on a yes, the chat tells you and writes the scenarios; a no is a line. Any chat can also ask it itself, with `evaluate_tests`.
27
+
26
28
  ## In the terminal
27
29
 
28
30
  | | |
@@ -65,7 +67,7 @@ In [debug mode](config.md#debug-mode) nothing is deleted. The `engine`'s choices
65
67
 
66
68
  ## Where there is one chat
67
69
 
68
- [pi](https://pi.dev)'s print, json and rpc modes - `turri -p "…"`, `--mode json`, `--mode rpc` - and a `turri` given its input on stdin have one chat and record none. So does `npm run chat`, pi with turri's extension loaded from its file. The command line's `turri regenerate`, `conform` and the rest have no chat.
70
+ [pi](https://pi.dev)'s print, json and rpc modes - `turri -p "…"`, `--mode json`, `--mode rpc` - and a `turri` given its input on stdin have one chat and record none, and no [test advisor](test-advisor.md). So does `npm run chat`, pi with turri's extension loaded from its file. The command line's `turri regenerate`, `conform` and the rest have no chat, and no test advisor either.
69
71
 
70
72
  ## In a host
71
73
 
package/docs/config.md CHANGED
@@ -9,11 +9,11 @@ A project says how its \*\*\*plain is built in `config.turri.yaml`, at the proje
9
9
  | `anthropic` | `anthropic/claude-opus-5-5` | `anthropic/claude-haiku-5-5` | `ANTHROPIC_API_KEY` |
10
10
  | `openai` | `openai/gpt-6-astra` | `openai/gpt-6-luna` | `OPENAI_API_KEY` |
11
11
  | `google` | `google/gemini-3.1-pro-preview` | `google/gemini-3.1-flash-lite` | `GEMINI_API_KEY` |
12
- | `amazon-bedrock`, Anthropic | `amazon-bedrock/<region>.anthropic.claude-opus-5-5` | `amazon-bedrock/<region>.anthropic.claude-haiku-5-5` | `AWS_PROFILE` or `AWS_BEARER_TOKEN_BEDROCK`, and `AWS_REGION` |
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` |
12
+ | `amazon-bedrock`, Anthropic | `amazon-bedrock/<region>.anthropic.claude-opus-5-5` | `amazon-bedrock/<region>.anthropic.claude-haiku-5-5` | `AWS_PROFILE` or `AWS_BEARER_TOKEN_BEDROCK` |
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` |
14
14
  | `other` | `anthropic/claude-opus-5-5` | `google/gemini-3.1-flash-lite` | `ANTHROPIC_API_KEY`, `GEMINI_API_KEY` |
15
15
 
16
- Amazon Bedrock asks three more things, from [pi](https://pi.dev)'s catalogue: whose models (`--maker`) - any maker [pi](https://pi.dev) has there, Anthropic, OpenAI, xAI, Meta, Mistral, Qwen, DeepSeek, Amazon, Moonshot, Z.ai, ... - the geography of the inference profile they run in (`--region`) - `global`, `us`, `eu`, `jp`, `au`, `apac`, `in`, `ca` or `us-gov`, as the maker's models are served, or `in-region`, a model served in the AWS region it is called in - and which two. The pair offered is turri's own where it has one - the table's, for Anthropic's and OpenAI's in the geographies they are served in - and otherwise the catalogue's: the strongest model that reasons to talk to, by price, and the cheapest costing at least a fifth of it to code, ties to the newest. Enter takes it; `c` chooses each from the maker's models there. It says which `AWS_REGION` to set for the geography: [pi](https://pi.dev) calls Bedrock in `AWS_REGION`, else the profile's region, else `us-east-1` - so every geography but `global`, `us` and `in-region` needs it set (`eu-central-1` for `eu`, `ap-northeast-1` for `jp`, `ap-southeast-2` for `au`, `ap-southeast-1` for `apac`, `ap-south-1` for `in`, `ca-central-1` for `ca`, `us-gov-west-1` for `us-gov`). A `config.turri.yaml` already there keeps everything but its two models, which it sets; `--force` writes the whole file again.
16
+ Amazon Bedrock asks three more things, from [pi](https://pi.dev)'s catalogue: whose models (`--maker`) - any maker [pi](https://pi.dev) has there, Anthropic, OpenAI, xAI, Meta, Mistral, Qwen, DeepSeek, Amazon, Moonshot, Z.ai, ... - the geography of the inference profile they run in (`--region`) - `global`, `us`, `eu`, `jp`, `au`, `apac`, `in`, `ca` or `us-gov`, as the maker's models are served, or `in-region`, a model served in the AWS region it is called in - and which two. The pair offered is turri's own where it has one - the table's, for Anthropic's and OpenAI's in the geographies they are served in - and otherwise the catalogue's: the strongest model that reasons to talk to, by price, and the cheapest costing at least a fifth of it to code, ties to the newest. Enter takes it; `c` chooses each from the maker's models there. The region is turri's to set, not the person's: [pi](https://pi.dev) calls Bedrock in `AWS_REGION`, else `AWS_DEFAULT_REGION`, else the `AWS_PROFILE`'s region, else `us-east-1` - so every geography but `global`, `us` and `in-region` needs a region of its own (`eu-central-1` for `eu`, `ap-northeast-1` for `jp`, `ap-southeast-2` for `au`, `ap-southeast-1` for `apac`, `ap-south-1` for `in`, `ca-central-1` for `ca`, `us-gov-west-1` for `us-gov`), and turri sets `AWS_REGION` to it in its own process before any model is called (`src/bedrock-region.ts`) - the chat, every command that calls a model, a host's session. `AWS_REGION` or `AWS_DEFAULT_REGION`, set, is always used instead, and so is the profile's region when it is in the geography. Models of two geographies that need two regions get none: one `AWS_REGION` serves every model, and `turri doctor` says which model needs which. `init-config` says which region turri will use. A `config.turri.yaml` already there keeps everything but its two models, which it sets; `--force` writes the whole file again.
17
17
 
18
18
  `--harness-model` and `--coding-model` name the two models instead, for any vendor: provider/model-id without a thinking level - `turri init-config --harness-model amazon-bedrock/global.xai.grok-4.7 --coding-model amazon-bedrock/global.xai.grok-4.6`. They are written wherever the vendor's own would be - the two models with their thinking, the commented-out `judge-model` and `models:` examples - and the vendor, maker and geography are read from them. `--judge-model` names the strong one the judging examples use, the harness model unless given. Each is checked against [pi](https://pi.dev)'s catalogue first: one it does not have, or that is not a chat model, is named, with the closest it has, and nothing is written.
19
19
 
@@ -21,7 +21,7 @@ Each is written with how hard it thinks - `harness-model: openai/gpt-6-astra:med
21
21
 
22
22
  They are an example, not a requirement - any model [pi](https://pi.dev) supports works, signed in any way [pi](https://pi.dev) 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](https://pi.dev) 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.
23
23
 
24
- 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.
24
+ 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`, `test-dir`, `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.
25
25
 
26
26
  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.
27
27
 
@@ -45,7 +45,7 @@ Each change says when it takes effect. None needs turri started again - what tur
45
45
  | 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` |
46
46
  | your next message | `rules-off` - for the conversation; a skill's agents from the next skill run |
47
47
  | 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`, `debug` |
48
- | the next time the work is planned | `conformance-tests`, `conformance-budget`, `max-specs-per-pulse`, `max-lines-per-pulse` |
48
+ | the next time the work is planned | `max-specs-per-pulse`, `max-lines-per-pulse` |
49
49
  | the next test run - the running pulse's too | the testing scripts, `testing-scripts-run-on` |
50
50
  | the next pulse that lands - the running one too | `release-after-pulse`, `sentinel` |
51
51
  | the next regeneration that names no `.plain` file | `module` |
@@ -57,6 +57,9 @@ A coding model chosen this session - `--coding-model`, or `engine` - gives way t
57
57
 
58
58
  ```yaml
59
59
  module: app.plain # what to build when no .plain file is named
60
+ conformance-tests: false # whether functional specs are conformance tested - false: none, the test advisor off (default: false)
61
+ test-dir: tests # the test plain files, a folder per module (default: tests)
62
+ base-folder: existing-app # what a codebase that requires no module starts from (default: nothing)
60
63
  harness-model: # the model you chat with
61
64
  model: anthropic/claude-opus-5-5
62
65
  thinking: high
@@ -66,7 +69,6 @@ coding-model: # every render (default: harness-model)
66
69
  judge-model: # the verdicts of a conformance run (default: coding-model)
67
70
  model: amazon-bedrock/eu.anthropic.claude-sonnet-5
68
71
  thinking: medium
69
- conformance-tests: true # write and run conformance tests where there are test reqs (default: false)
70
72
  unittests-script: test_scripts/run_unittests_python.sh
71
73
  conformance-tests-script: test_scripts/run_conformance_tests_python.sh
72
74
  testing-scripts-run-on: copy # what the testing scripts run on: copy - a fresh copy (default: in-place - the code itself)
@@ -83,14 +85,16 @@ models: # each agent role's model, thinking and tur
83
85
  | `harness-model` | the model `turri` starts on - the one you talk to - and, in the conversation, the planner that cuts the work into jobs (on whatever model the chat is on when it plans); under `turri regenerate`, the planner too | [pi](https://pi.dev)'s configured model |
84
86
  | `coding-model` | every regeneration: functionalities, \*\*\*plain diffs, conformance tests, repairs, planning \*\*\*plain diffs, the explorer | `harness-model` |
85
87
  | `judge-model` | the judge and the test review of a conformance run | `coding-model` |
86
- | `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`: no new ones written - until the conversation asks with `conform` - and the existing ones kept up to date: a functional spec that has conformance tests and is regenerated gets a conformance pulse for it alone once its code lands | `false` |
87
- | `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 |
88
88
  | `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. A module's first pulse of one functional spec - the project set up and the smallest thing that runs - lands on its unit tests with no review - see [regenerating the code](regenerating.md#the-code-and-its-unit-tests-are-reviewed) | `false` |
89
89
  | `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` |
90
90
  | `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 \*\*\*plain-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 \*\*\*plain is written. `turri init-config` writes it with `integration-embedded`, `integration-embedded-testing` and `integration-standalone` - take them out when the project writes an integration against a REST API. The project's alone | none |
91
91
  | `allow-to-stop-jobs` | `true` or `false`: whether turri stops a running job \*\*\*plain has moved on from - a functional spec it regenerates changed, or a file one links was edited - rolls it back and regenerates \*\*\*plain 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` |
92
92
  | `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 releases it, following the project's release guidance as the chat finds it (what was passed to `release` this conversation, AGENTS.md, the project's skills) for how, or to `dist/<module>` without any - 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. `turri init-config` writes `true` | `false` |
93
93
  | `sentinel` | `ask`, `true` or `false`: whether a chat of turri's own, the sentinel, gets every pulse that finishes - checks it, tests what was released under `release-after-pulse`, and puts what needs you as a notice in the chat you are in - instead of the chat that asked for it. `ask`: you are asked, with what it does, before it first opens in a session - see [starting it](sentinel.md#starting-it); `true`: it opens without asking. `/sentinel` sets it from the chat. `turri init-config` writes `ask` | `ask` |
94
+ | `test-advisor` | `true` or `false`: whether the [test advisor](test-advisor.md) starts by itself - in the chat and a host, never headless - checking each new or changed functional spec with no scenarios in the background for whether it needs testing - on a yes, the chat writes its \*\*\*test reqs\*\*\*, conformance testing script and scenarios. `false` turns off only that: the chat's `evaluate_tests` still works, and scenarios you ask the chat for are written as before. `turri init-config` writes `true` | `true` |
95
+ | `conformance-tests` | whether functional specs are conformance tested - black-box tests of the built software against the scenarios of their test plain files, run with the whole suite as more lands. `false`: none - no scenarios written or tested, no conformance testing script, the test advisor and the chat's `conform` and `evaluate_tests` off. The person asking for them in the chat, or agreeing when the chat offers them, turns them on - see [conformance tests](#conformance-tests). A stack's `config.turri.<stack>.yaml` can set its own | `false` |
96
+ | `test-dir` | the folder of the test plain files, by path from the project root: a module's are every `.plain` file in `<test-dir>/<module>/`, each a functional spec's conformance and acceptance scenarios - see [test plain files](parser.md#test-plain-files). A stack's `config.turri.<stack>.yaml` can set its own | `tests` |
97
+ | `base-folder` | a folder, by path from the project root, that a codebase requiring no other module starts from instead of nothing - an existing codebase to build on, files to use (images, animations, fonts), or both. It is copied in once, before the codebase's first pulse, and never written to: from a git repo what git sees, else every file but `.git` and installed dependencies. The \*\*\*plain may refer to it, and link into it; a codebase built on another starts from that one's code, base folder and all. A stack's `config.turri.<stack>.yaml` can name its own - see [the base folder](regenerating.md#the-base-folder) | none: the codebase starts empty |
94
98
  | `unittests-script` | the unit testing script, by path from the project root - it runs the code's static checks too, exiting 80 when only they fail (see [the static checks](regenerating.md#the-static-checks)) | looked for - see below |
95
99
  | `conformance-tests-script` | the conformance testing script, by path from the project root | looked for - see below |
96
100
  | `prepare-environment-script` | optional: run as `<script> <build>` before every run of the conformance testing script, which runs only once it passes - see [the testing scripts](regenerating.md#the-testing-scripts). turri never writes one | the one `prepare_environment*.sh` at the root or in `test_scripts/`, else none |
@@ -107,7 +111,7 @@ models: # each agent role's model, thinking and tur
107
111
  | `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` |
108
112
  | `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` |
109
113
 
110
- 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`.
114
+ Keys are written with dashes; underscores are read the same (`mutation_testing`). 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`.
111
115
 
112
116
  ## Models per role
113
117
 
@@ -118,7 +122,7 @@ Keys are written with dashes; underscores are read the same (`conformance_tests`
118
122
  | `default` | every role not named below - but the conversation's side |
119
123
  | `chat` | `turri`'s model - the same as `harness-model`, which it wins over |
120
124
  | `sentinel` | [the sentinel](sentinel.md): checks every finished pulse, and tests the release. Unnamed, the chat's model |
121
- | `chooser`, `planner` | the conversation's side: the conformance chooser of `turri regenerate`, the planner's agents. Unnamed, the chat's model |
125
+ | `planner` | the conversation's side: the planner's agents. Unnamed, the chat's model |
122
126
  | `diagnosis` | the diagnosis of a job that failed for good: why it did not land, and what to do. Unnamed, the coding model the job ran on, thinking medium |
123
127
  | `release` | `turri release`'s agent and release-after-pulse's: it follows steps - a script, a start command - so it runs on the coding model, thinking low |
124
128
  | `coding` | the coding agent, the code fixer of a conformance run and the repair agent - the same as `coding-model`, which it wins over. `--model` on the command line, or a model chosen in the conversation (`engine`), wins over both |
@@ -129,10 +133,11 @@ Keys are written with dashes; underscores are read the same (`conformance_tests`
129
133
  | `judge` | the judge of a failing conformance run - the same as `judge-model`, which it wins over |
130
134
  | `arbiter` | the arbiters that weigh a second review |
131
135
  | `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` |
136
+ | `advisor` | the [test advisor](test-advisor.md): classifying a new or changed functional spec, its probes, readers and verifier |
132
137
 
133
138
  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.
134
139
 
135
- 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 \*\*\*plain that leaves 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](https://pi.dev) sets it.
140
+ 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`, `advisor`), which work from \*\*\*plain that leaves little to guess and take many turns, and **medium** for the ones that judge (`reviewer`, `test-reviewer`, `judge`, `arbiter`, `debugger`, `planner`, `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](https://pi.dev) sets it.
136
141
 
137
142
  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](https://pi.dev) sends them none.
138
143
 
@@ -164,15 +169,15 @@ They are defaults. What is asked for wins over them:
164
169
  | coding | `turri --coding-model <m>`, `engine` in the conversation |
165
170
  | judge | - |
166
171
 
167
- `turri regenerate`, `conform` and `change-plain` 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.
172
+ `turri regenerate`, `conform` and `change-plain` read `--harness-model`, `--coding-model` (or `--model`), `--judge-model` and `--review` 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.
168
173
 
169
174
  A job keeps the model it was queued with: choosing another holds for what is queued after.
170
175
 
171
176
  ## Conformance tests
172
177
 
173
- `conformance-tests:` is the one switch, and the chat and every regeneration follow it. `false` writes no new conformance tests, and keeps the ones there are up to date: a functional spec that has conformance tests - it is in `tests/.turri.json` - and is added, changed, regenerated again or taken out in the code gets a conformance pulse once its code lands, for it alone, the whole suite run with it. A functional spec with none gets none, though others of its module have them, and a module with none gets no conformance pulse at all. 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 `change-plain` - for that run, the file left as it is - a regeneration does otherwise.
178
+ `conformance-tests: true` turns them on, a stack's `config.turri.<stack>.yaml` able to say its own. Unset, they are off, and `turri init-config` writes `conformance-tests: false`: no scenarios are written or tested, no conformance testing script is written, no conformance pulse runs - in the work loop, from `conform` or `turri conform` - the test advisor is off, and the chat has neither `conform` nor `evaluate_tests`. Test plain files already there are kept and parsed, and not tested: `parse` and `drift` say so. The chat always knows what they are, that they are off, and how they are turned on, and may offer them - once, never turning them on unasked. You asking it for conformance tests or testing scenarios, or agreeing when it offers them, turns them on: it writes `conformance-tests: true` - into the stack's file when that names the key, else `config.turri.yaml` - in effect at once, and kept for the sessions after. So does `/turri-config conformance-tests true`.
174
179
 
175
- The chat writes `conformance-tests: false` into a new project unless you ask for tests.
180
+ On, what is tested is the functional specs with scenarios - the conformance and acceptance scenarios of each one's test plain file, `<test-dir>/<module>/<func-id>.plain` - in every module with `***test reqs***`. A functional spec with no test plain file is not tested, and a module with no functional spec with scenarios gets no conformance pulse at all - but keeps the codebase's existing tests passing. `test-dir` says where the test plain files are. To have a functional spec tested, write its scenarios: the chat writes them with `change_plain` when you ask for conformance tests (see [conformance tests](regenerating.md#conformance-tests)).
176
181
 
177
182
  ## The testing scripts
178
183
 
@@ -224,7 +229,7 @@ Their values never appear in what an agent is shown or what turri writes: each i
224
229
  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:
225
230
 
226
231
  ```
227
- config.turri.yaml # the project's: harness-model, coding-model, conformance-tests
232
+ config.turri.yaml # the project's: harness-model, coding-model, review
228
233
  config.turri.backend.yaml # the stack backend: its testing scripts
229
234
  config.turri.frontend.yaml # the stack frontend: its testing scripts, and a coding model of its own
230
235
  backend.plain # import: [base, python_fastapi_template]
package/docs/deploy.md CHANGED
@@ -6,7 +6,7 @@ Ask to try it - "let me try it", "run the app" - at any time, even while a regen
6
6
 
7
7
  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:
8
8
 
9
- - **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. Whether to release after every pulse is `release-after-pulse`'s to say - see [after every pulse](#after-every-pulse). 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.
9
+ - **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. Whether to release after every pulse is `release-after-pulse`'s to say - see [after every pulse](#after-every-pulse). 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, and nor is the \*\*\*plain: its file tools refuse a `.plain` file - a module or a test plain file - as they refuse `plain_modules`.
10
10
  - **There is none.** The default: it is started from `dist/<module>`, as below, as best it can be.
11
11
 
12
12
  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.
@@ -36,6 +36,7 @@ The workflow signs in to npm with npm's trusted publishing (OIDC), not a token:
36
36
  | `src/extension.ts` | the [pi](https://pi.dev) extension: every tool and command the conversation has - and `createTurriCore`, the session it is built into |
37
37
  | `src/chats.ts`, `src/chat-scope.ts`, `src/chat-records.ts` | the session's [chats](chats.md): which chat a pulse is told to, each chat's scope - its id and stack - and `.turri/chats.json` |
38
38
  | `src/sentinel.ts`, `src/sentinel-chat.ts` | [the sentinel](sentinel.md): its prompt, what it is told of a pulse, its fenced tools, its guidance; notices - their cards, the terminal's dialog, their answers |
39
+ | `src/regenerate/advisor-runs.ts`, `src/regenerate/test-advisor.ts`, `src/regenerate/advisor-records.ts`, `src/advisor-chat.ts` | [the test advisor](test-advisor.md): which functional specs it takes and when, its model calls, its file in `.turri/advisor/`, and how its verdicts reach the chat |
39
40
  | `src/chat-terminal.ts`, `src/chat-ui.ts`, `src/chat-commands.ts` | the terminal's chats: [pi](https://pi.dev)'s screen switched between live sessions, a hidden chat's stand-in for it, `/chat` and its keys |
40
41
  | `src/host-session.ts` | `createTurri`, the session for a host |
41
42
  | `src/skill.ts` | parses `SKILL.md` into steps and gates |
@@ -45,7 +46,7 @@ The workflow signs in to npm with npm's trusted publishing (OIDC), not a token:
45
46
  | `src/pi.ts` | [pi](https://pi.dev) session factories for executors, sub-agents and judges |
46
47
  | `src/spec-tools.ts` | `change_plain` |
47
48
  | `src/loop-tools.ts` | `regenerate`, `drift` and `halt` - one definition each, for the conversation and the skills alike |
48
- | `src/plain/` | the [\*\*\*plain](https://plainlang.org/docs/) parser - see [parser](parser.md) - and `highlight.ts`, which highlights \*\*\*plain with plyn's grammar, `plain.tmLanguage.json` (`npm run grammar:sync` refreshes it from [plyn](https://github.com/plainlang/plyn)) |
49
+ | `src/plain/` | the [\*\*\*plain](https://plainlang.org/docs/) parser - see [parser](parser.md) - and `highlight.ts`, which highlights \*\*\*plain with turri's own grammar, `plain.tmLanguage.json` - started from [plyn](https://github.com/plainlang/plyn)'s at `f9c02b8`, and changed here since: test plain files' sections and keys, the `# <id>` heading |
49
50
  | `src/regenerate/conformance.ts` | conformance tests: writing them, and fixing the test or the code until they pass |
50
51
  | `src/regenerate/regenerate.ts`, `src/regenerate/conform.ts` | a code job - a \*\*\*plain diff regenerated in the code - and a conformance job |
51
52
  | `src/regenerate/loop.ts`, `src/regenerate/records.ts`, `src/regenerate/drift.ts`, `src/regenerate/jobs.ts` | the work loop, the records and the work derived from them, and background jobs |
package/docs/headless.md CHANGED
@@ -18,7 +18,7 @@ Check \*\*\*plain parses, without spending anything:
18
18
 
19
19
  ```bash
20
20
  cd ~/my-project # the directory that holds the spec
21
- turri validate app.plain
21
+ turri parse app.plain
22
22
  ```
23
23
 
24
24
  ## Run it
@@ -49,19 +49,17 @@ coding-model: # the model every agent runs on, and h
49
49
  model: anthropic/claude-sonnet-5
50
50
  thinking: medium
51
51
  judge-model: anthropic/claude-opus-5-5 # the judge and the test review (default: coding-model)
52
- conformance-tests: true # write and run conformance tests where there are test reqs (default: false)
53
52
  ```
54
53
 
55
- The same file names the [testing scripts](regenerating.md#the-testing-scripts); every key is in [the project config](config.md). `turri regenerate`, `change-plain` and `conform` take five of its keys on the command line too - `--harness-model`, `--coding-model` (`--model` is the same), `--judge-model`, `--review` and, but for `conform`, `--conformance-tests`. Each is read as if the file had it, in its place: it takes that key's value, and every key keeps its place in the order the config resolves them in - a `models:` entry still wins over `harness-model`, `coding-model` or `judge-model`, the planner and the conformance chooser run on the harness model, the judge falls back on the coding model. So a run with the options is the same as one, or a chat, with those keys in `config.turri.yaml` - and a `config.yaml` the project has is left as it is. A project whose parts are on different stacks keeps each stack's settings in `config.turri.<stack>.yaml` beside it ([stacks](config.md#stacks)). Choose the one to build with `--stack <name>` - on any command: `regenerate`, `conform`, `change-plain`, `glimpse`, `release`, `cultivate` - or `TURRI_STACK`: `turri regenerate backend.plain --stack backend`. With none chosen, `config.turri.yaml` alone is used; a stack the project has no file for is refused.
54
+ The same file names the [testing scripts](regenerating.md#the-testing-scripts); every key is in [the project config](config.md). `turri regenerate`, `change-plain` and `conform` take four of its keys on the command line too - `--harness-model`, `--coding-model` (`--model` is the same), `--judge-model` and `--review`. Each is read as if the file had it, in its place: it takes that key's value, and every key keeps its place in the order the config resolves them in - a `models:` entry still wins over `harness-model`, `coding-model` or `judge-model`, the planner runs on the harness model, the judge falls back on the coding model. So a run with the options is the same as one, or a chat, with those keys in `config.turri.yaml` - and a `config.yaml` the project has is left as it is. A project whose parts are on different stacks keeps each stack's settings in `config.turri.<stack>.yaml` beside it ([stacks](config.md#stacks)). Choose the one to build with `--stack <name>` - on any command: `regenerate`, `conform`, `change-plain`, `glimpse`, `release`, `cultivate` - or `TURRI_STACK`: `turri regenerate backend.plain --stack backend`. With none chosen, `config.turri.yaml` alone is used; a stack the project has no file for is refused.
56
55
 
57
56
  Useful options - `turri regenerate --help` lists all of them:
58
57
 
59
58
  | | |
60
59
  | --- | --- |
61
- | `--harness-model <provider/id>` | `harness-model`: the planner and the conformance chooser |
60
+ | `--harness-model <provider/id>` | `harness-model`: the planner |
62
61
  | `--coding-model <provider/id>` | `coding-model` (`--model` too): the agents that build - with `:level` for how hard it thinks (`provider/id:high`); not given, the harness model's |
63
62
  | `--judge-model <provider/id>` | `judge-model`: the judge and the test review; not given, the coding model |
64
- | `--conformance-tests <all\|chosen\|module\|false>` | `conformance-tests`, with its values (`true` is `all`) |
65
63
  | `--review <true\|false>` | `review`: whether the code and its tests are reviewed once they pass |
66
64
  | `--mutation-testing <true\|false>` | `mutation-testing`: whether the coding agent and the reviewer have `can_it_fail` |
67
65
  | `--stack <name>` | build with the stack's `config.turri.<name>.yaml` over `config.turri.yaml`; default, `TURRI_STACK`, else none |
@@ -73,7 +71,7 @@ Useful options - `turri regenerate --help` lists all of them:
73
71
 
74
72
  An option a command does not take is refused, not ignored.
75
73
 
76
- `turri regenerate` queues the jobs the chat's `regenerate` does - a \*\*\*plain diff that brings what is built in line, when it no longer matches \*\*\*plain, then one regenerate functionality job per functional spec not built, each with its conformance job - and runs them all to the end, the queue master reworking them as in the chat (see [a whole module](regenerating.md#a-whole-module)). Conformance tests follow `conformance-tests:` in `config.turri.yaml`, or `--conformance-tests`.
74
+ `turri regenerate` queues the jobs the chat's `regenerate` does - a \*\*\*plain diff that brings what is built in line, when it no longer matches \*\*\*plain, then one regenerate functionality job per functional spec not built, then the conformance jobs of the functional specs with scenarios - and runs them all to the end, the queue master reworking them as in the chat (see [a whole module](regenerating.md#a-whole-module)). What is conformance tested is the scenarios: a functional spec with no test plain file, or an empty one, is not.
77
75
 
78
76
  ## In the morning
79
77
 
@@ -104,15 +102,14 @@ A module that `requires` others is built in its own codebase on top of theirs: t
104
102
 
105
103
  ```jsonc
106
104
  {
107
- "schema_version": 1,
105
+ "schema_version": 2,
108
106
  "turri": { "version": "0.1.1", "git_commit": "48dacfc…", "git_dirty": false }, // commit: null outside a clone
109
107
  "command": ["regenerate", "app.plain", "--model", "…", "--report", "report.json"],
110
108
  "spec_file": "/work/app.plain", "project_dir": "/work", "build_dir": "/work/out", // build_dir: null without one
111
- "conformance_tests": "all", // all | chosen | module | false
112
109
  "review": false,
113
110
  "mutation_testing": true,
114
111
  "models": {
115
- "harness": { "model": "…", "thinking": "medium" }, // the planner, the chooser
112
+ "harness": { "model": "…", "thinking": "medium" }, // the planner
116
113
  "coding": { "model": "…", "thinking": "low" },
117
114
  "judge": { "model": "…", "thinking": "medium" },
118
115
  "observed": { "coding": ["provider/id:low"], "planner": ["provider/id:medium"] } // what each role really ran on
@@ -129,7 +126,7 @@ A module that `requires` others is built in its own codebase on top of theirs: t
129
126
  "llm_calls": 0, "agent_turns": 0, "compactions": 0, "provider_retries": 0, "provider_stalls": 0, "turns_stopped": 0, "model_seconds": 0
130
127
  },
131
128
  "in_pulses": { }, // the pulses' usage added up - the same fields
132
- "outside_pulses": { }, // the planner, the conformance chooser, a failed pulse's diagnosis
129
+ "outside_pulses": { }, // the planner, a failed pulse's diagnosis
133
130
  "by_model": { "provider/id:low": { } },
134
131
  "by_role": { "coding": { }, "reviewer": { }, "planner": { } },
135
132
  "by_pulse_kind": { "code": { }, "conformance": { } }
@@ -147,10 +144,10 @@ A module that `requires` others is built in its own codebase on top of theirs: t
147
144
  }]
148
145
  },
149
146
  "functionalities": {
150
- "total": { "specified": 12, "completed": 10, "conformance_tested": 8 },
147
+ "total": { "specified": 12, "with_scenarios": 9, "completed": 10, "conformance_tested": 8 },
151
148
  "modules": [
152
- { "module": "base", "specified": 4, "completed": 4, "conformance_tested": 4, "incomplete_frids": [] },
153
- { "module": "app", "specified": 8, "completed": 6, "conformance_tested": 4, "incomplete_frids": ["7", "8"] }
149
+ { "module": "base", "specified": 4, "with_scenarios": 4, "completed": 4, "conformance_tested": 4, "incomplete_func_ids": [] },
150
+ { "module": "app", "specified": 8, "with_scenarios": 5, "completed": 6, "conformance_tested": 4, "incomplete_func_ids": ["export-csv", "import-csv"] }
154
151
  ],
155
152
  "codebases": ["plain_modules/app/code"]
156
153
  },
@@ -179,7 +176,7 @@ A module that `requires` others is built in its own codebase on top of theirs: t
179
176
 
180
177
  **Turn incidents.** Each time the model provider failed for a moment and [pi](https://pi.dev) or turri waited it out before trying the request again, each time the provider sent nothing back on a request for two minutes, and each turn turri stopped itself - an agent going round in a circle, its calls failing again and again, its time up - after which the run carried on. The provider failing or stalling is printed as it happens, in orange, under the pulse; a stop is the work's normal course and is only listed. They are counted in the usage as `provider_retries`, `provider_stalls` and `turns_stopped`. Many of any point at the model, not \*\*\*plain: a provider at its limits, or a model too small for the role it was given.
181
178
 
182
- **Completed functional specs** - the pass rate, the figure to compare runs by. A functional spec is completed when the code record of the codebase the run delivers - the furthest-built of the chain, the one `--build-dir` exports - as last committed, holds it as \*\*\*plain has it now: the same text, every file it links holding the same, no definition it uses changed, and not marked to regenerate again. A record moves only when a pulse lands, and a pulse lands only once the code's unit tests pass (its conformance tests too, when they are on), so completed means landed and passing. Each module counts its own functional specs: a module below the tip counts from what the tip's code was built on, and a module above the delivered codebase has none completed. `conformance_tested` is those of the completed ones whose conformance tests are recorded as written for them as they are now (`plain_modules/<module>/tests/.turri.json`).
179
+ **Completed functional specs** - the pass rate, the figure to compare runs by. A functional spec is completed when the code record of the codebase the run delivers - the furthest-built of the chain, the one `--build-dir` exports - as last committed, holds it as \*\*\*plain has it now: the same text, every file it links holding the same, no definition it uses changed, and not marked to regenerate again. A record moves only when a pulse lands, and a pulse lands only once the code's unit tests pass (its conformance tests too, when they are on), so completed means landed and passing. Each module counts its own functional specs: a module below the tip counts from what the tip's code was built on, and a module above the delivered codebase has none completed. `with_scenarios` is those with scenarios - the ones that are tested; one with no test plain file, or an empty one, is not - and `conformance_tested` those of the completed ones whose conformance tests are recorded as written for them as they are now, their text and their scenarios, in the tests record of the delivered codebase, whose suite holds the chain's (`plain_modules/<tip>/tests/.turri.json`): tested of specified is `conformance_tested` of `with_scenarios`.
183
180
 
184
181
  ## If it stopped
185
182
 
@@ -188,10 +185,10 @@ Run the same command again. Functionalities already built from the current \*\*\
188
185
  ## Rebuilding one functionality
189
186
 
190
187
  ```bash
191
- turri regenerate app.plain 3
188
+ turri regenerate app.plain app:add-task
192
189
  ```
193
190
 
194
- It rebuilds just functionality 3 over the code that already exists - after its \*\*\*plain changed, or as it is - without rebuilding the ones before it. To change what it does, change its \*\*\*plain first: \*\*\*plain is what the code is built from, and a change made there lasts. Then it updates the functionality's conformance tests and runs every conformance test in the codebase, since a change can break something built later as easily as something built earlier. It works in the codebase the functionality now lives in: when later modules are built on top of this one, the furthest-built of them. It exits `0` when everything passes, and refuses when there is no code yet - regenerate the module first.
191
+ It rebuilds just `app:add-task` over the code that already exists - after its \*\*\*plain changed, or as it is - without rebuilding the ones before it. To change what it does, change its \*\*\*plain first: \*\*\*plain is what the code is built from, and a change made there lasts. Then it updates the functionality's conformance tests and runs every conformance test in the codebase, since a change can break something built later as easily as something built earlier. It works in the codebase the functionality now lives in: when later modules are built on top of this one, the furthest-built of them. It exits `0` when everything passes, and refuses when there is no code yet - regenerate the module first.
195
192
 
196
193
  Several changes do not need one command each: after editing \*\*\*plain, re-running `turri regenerate` brings the code up to it - one \*\*\*plain diff for what changed in what is built, then the functional specs not built yet.
197
194
 
@@ -202,7 +199,7 @@ A benchmark or CI task runs it with no terminal and nothing to ask, so give it e
202
199
  ```bash
203
200
  turri regenerate app.plain --harness-model amazon-bedrock/eu.anthropic.claude-opus-5-5 \
204
201
  --coding-model amazon-bedrock/eu.anthropic.claude-sonnet-5-5 \
205
- --conformance-tests all --review false --judge-model amazon-bedrock/eu.anthropic.claude-opus-5-5 \
202
+ --review false --judge-model amazon-bedrock/eu.anthropic.claude-opus-5-5 \
206
203
  --start-over --build-dir /out/build --report /out/report.json < /dev/null
207
204
  ```
208
205
 
@@ -216,7 +213,7 @@ turri regenerate app.plain --harness-model amazon-bedrock/eu.anthropic.claude-op
216
213
  It exits 1 on anything marked `✗`.
217
214
  - **Without bubblewrap:** a container that cannot make user namespaces - no `--security-opt seccomp=unconfined` - has no OS sandbox. turri runs anyway, the command check and the audit holding alone under the agents' commands; `turri doctor` shows it as `!`, not `✗`. Installing the `bubblewrap` package is worth it where it can start.
218
215
  - **As another user:** run it as the user who will own `plain_modules/`. git refuses a repository another user made (`dubious ownership`), so do not let root create it first.
219
- - **Amazon Bedrock:** `AWS_BEARER_TOKEN_BEDROCK` (or the usual AWS credentials) and `AWS_REGION` are enough - no [pi](https://pi.dev) login. An `eu.` inference profile needs an EU region. A model id [pi](https://pi.dev) does not know stops the first pulse; `turri --list-models bedrock` lists the ones it does.
216
+ - **Amazon Bedrock:** `AWS_BEARER_TOKEN_BEDROCK` (or the usual AWS credentials) is enough - no [pi](https://pi.dev) login. An `eu.` inference profile needs an EU region, which turri sets itself, as `AWS_REGION`, unless one is set ([config](config.md)). A model id [pi](https://pi.dev) does not know stops the first pulse; `turri --list-models bedrock` lists the ones it does.
220
217
  - **A project with only a `config.yaml`:** it is read while there is no `config.turri*.yaml` - `unittests-script`, `conformance-tests-script` and `prepare-environment-script` included, relative to the project; the keys turri does not know are ignored. Do not write a `config.turri.yaml` beside it to turn on conformance tests or review: from then on `config.yaml` is not read. The options above do it instead.
221
218
  - **Long test suites:** a testing script run is stopped after 120 seconds; set `TURRI_COMMAND_TIMEOUT` (seconds) for more.
222
219