@turri-dev/cli 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (315) hide show
  1. package/.pi/themes/turri-dark.json +80 -0
  2. package/.pi/themes/turri-light.json +82 -0
  3. package/LICENSE +21 -0
  4. package/README.md +272 -2
  5. package/assets/jellyfish/dark-00.png +0 -0
  6. package/assets/jellyfish/dark-01.png +0 -0
  7. package/assets/jellyfish/dark-02.png +0 -0
  8. package/assets/jellyfish/dark-03.png +0 -0
  9. package/assets/jellyfish/dark-04.png +0 -0
  10. package/assets/jellyfish/dark-05.png +0 -0
  11. package/assets/jellyfish/dark-06.png +0 -0
  12. package/assets/jellyfish/dark-07.png +0 -0
  13. package/assets/jellyfish/dark-08.png +0 -0
  14. package/assets/jellyfish/dark-09.png +0 -0
  15. package/assets/jellyfish/dark-10.png +0 -0
  16. package/assets/jellyfish/dark-11.png +0 -0
  17. package/assets/jellyfish/dark-12.png +0 -0
  18. package/assets/jellyfish/dark-13.png +0 -0
  19. package/assets/jellyfish/dark-14.png +0 -0
  20. package/assets/jellyfish/fallback.txt +252 -0
  21. package/assets/jellyfish/light-00.png +0 -0
  22. package/assets/jellyfish/light-01.png +0 -0
  23. package/assets/jellyfish/light-02.png +0 -0
  24. package/assets/jellyfish/light-03.png +0 -0
  25. package/assets/jellyfish/light-04.png +0 -0
  26. package/assets/jellyfish/light-05.png +0 -0
  27. package/assets/jellyfish/light-06.png +0 -0
  28. package/assets/jellyfish/light-07.png +0 -0
  29. package/assets/jellyfish/light-08.png +0 -0
  30. package/assets/jellyfish/light-09.png +0 -0
  31. package/assets/jellyfish/light-10.png +0 -0
  32. package/assets/jellyfish/light-11.png +0 -0
  33. package/assets/jellyfish/light-12.png +0 -0
  34. package/assets/jellyfish/light-13.png +0 -0
  35. package/assets/jellyfish/light-14.png +0 -0
  36. package/bin/turri.mjs +29 -0
  37. package/dist/ask.js +149 -0
  38. package/dist/brand.js +50 -0
  39. package/dist/btw.js +174 -0
  40. package/dist/chat-models.js +37 -0
  41. package/dist/chat-skills.js +18 -0
  42. package/dist/cli.js +178 -0
  43. package/dist/config-command.js +197 -0
  44. package/dist/config-edit.js +367 -0
  45. package/dist/config.js +489 -0
  46. package/dist/conform-cli.js +29 -0
  47. package/dist/cultivate-cli.js +110 -0
  48. package/dist/drift-cli.js +25 -0
  49. package/dist/environment.js +70 -0
  50. package/dist/extension.js +2372 -0
  51. package/dist/genome.js +301 -0
  52. package/dist/graph.js +246 -0
  53. package/dist/identity.js +35 -0
  54. package/dist/init-config.js +511 -0
  55. package/dist/judge.js +62 -0
  56. package/dist/lineage-cli.js +13 -0
  57. package/dist/loop-cli.js +132 -0
  58. package/dist/loop-tools.js +225 -0
  59. package/dist/mature-tools.js +193 -0
  60. package/dist/model-check.js +117 -0
  61. package/dist/module-report.js +9 -0
  62. package/dist/pi-launch.js +31 -0
  63. package/dist/pi.js +813 -0
  64. package/dist/plain/check.js +76 -0
  65. package/dist/plain/concepts.js +213 -0
  66. package/dist/plain/errors.js +43 -0
  67. package/dist/plain/files.js +57 -0
  68. package/dist/plain/highlight.js +195 -0
  69. package/dist/plain/index.js +15 -0
  70. package/dist/plain/liquid.js +129 -0
  71. package/dist/plain/markdown.js +208 -0
  72. package/dist/plain/parser.js +752 -0
  73. package/dist/plain/plain.tmLanguage.json +124 -0
  74. package/dist/plain/spec.js +291 -0
  75. package/dist/plain/stdlib.js +44 -0
  76. package/dist/question-dialog.js +125 -0
  77. package/dist/questioning.js +109 -0
  78. package/dist/quiet.js +125 -0
  79. package/dist/regenerate/activity.js +187 -0
  80. package/dist/regenerate/agent-env.js +190 -0
  81. package/dist/regenerate/agent-shell.js +114 -0
  82. package/dist/regenerate/arbiter.js +133 -0
  83. package/dist/regenerate/audit.js +203 -0
  84. package/dist/regenerate/cases.js +83 -0
  85. package/dist/regenerate/change-view.js +102 -0
  86. package/dist/regenerate/choose-conformance.js +117 -0
  87. package/dist/regenerate/chunk-plan.js +625 -0
  88. package/dist/regenerate/codebase.js +75 -0
  89. package/dist/regenerate/command-check.js +312 -0
  90. package/dist/regenerate/compaction.js +20 -0
  91. package/dist/regenerate/confine.js +310 -0
  92. package/dist/regenerate/conform.js +133 -0
  93. package/dist/regenerate/conformance-agents.js +955 -0
  94. package/dist/regenerate/conformance.js +936 -0
  95. package/dist/regenerate/conversation-writes.js +100 -0
  96. package/dist/regenerate/credentials.js +88 -0
  97. package/dist/regenerate/debug-log.js +228 -0
  98. package/dist/regenerate/debugger.js +90 -0
  99. package/dist/regenerate/delivery.js +19 -0
  100. package/dist/regenerate/diagnose-job.js +40 -0
  101. package/dist/regenerate/diagnose.js +81 -0
  102. package/dist/regenerate/diff-view.js +240 -0
  103. package/dist/regenerate/drift.js +194 -0
  104. package/dist/regenerate/engine.js +118 -0
  105. package/dist/regenerate/environment-error.js +220 -0
  106. package/dist/regenerate/job-log.js +102 -0
  107. package/dist/regenerate/job-panel.js +336 -0
  108. package/dist/regenerate/jobs-tree.js +300 -0
  109. package/dist/regenerate/jobs.js +427 -0
  110. package/dist/regenerate/lanes.js +32 -0
  111. package/dist/regenerate/lineage.js +384 -0
  112. package/dist/regenerate/loop.js +1435 -0
  113. package/dist/regenerate/masking.js +95 -0
  114. package/dist/regenerate/notes.js +397 -0
  115. package/dist/regenerate/os-sandbox.js +243 -0
  116. package/dist/regenerate/paths.js +165 -0
  117. package/dist/regenerate/plain-palette.js +83 -0
  118. package/dist/regenerate/prompt.js +704 -0
  119. package/dist/regenerate/records.js +294 -0
  120. package/dist/regenerate/regenerate.js +598 -0
  121. package/dist/regenerate/regression.js +181 -0
  122. package/dist/regenerate/release.js +262 -0
  123. package/dist/regenerate/requires.js +241 -0
  124. package/dist/regenerate/resources.js +164 -0
  125. package/dist/regenerate/self-check.js +111 -0
  126. package/dist/regenerate/services.js +155 -0
  127. package/dist/regenerate/shell.js +319 -0
  128. package/dist/regenerate/side-panel.js +278 -0
  129. package/dist/regenerate/spec-map-view.js +574 -0
  130. package/dist/regenerate/spec-map.js +561 -0
  131. package/dist/regenerate/spec-steps.js +527 -0
  132. package/dist/regenerate/state.js +10 -0
  133. package/dist/regenerate/steer.js +91 -0
  134. package/dist/regenerate/steering.js +119 -0
  135. package/dist/regenerate/stop-report.js +161 -0
  136. package/dist/regenerate/submit-work.js +71 -0
  137. package/dist/regenerate/test-kinds.js +124 -0
  138. package/dist/regenerate/test-scripts.js +695 -0
  139. package/dist/regenerate/testing.js +406 -0
  140. package/dist/regenerate/transcript-view.js +1 -0
  141. package/dist/regenerate/unit-gate.js +20 -0
  142. package/dist/regenerate/unit-review.js +347 -0
  143. package/dist/regenerate/web.js +256 -0
  144. package/dist/regenerate/workspace.js +99 -0
  145. package/dist/regenerate-cli.js +68 -0
  146. package/dist/release-agent.js +114 -0
  147. package/dist/release-cli.js +131 -0
  148. package/dist/release-tools.js +148 -0
  149. package/dist/review/live.js +165 -0
  150. package/dist/rules.js +47 -0
  151. package/dist/self-invocation.js +110 -0
  152. package/dist/setup.js +245 -0
  153. package/dist/skill-progress.js +78 -0
  154. package/dist/skill.js +149 -0
  155. package/dist/skills.js +74 -0
  156. package/dist/spec-diff-cli.js +37 -0
  157. package/dist/spec-tools.js +155 -0
  158. package/dist/stack.js +158 -0
  159. package/dist/stacks.js +97 -0
  160. package/dist/stdlib.js +100 -0
  161. package/dist/terminal-images.js +46 -0
  162. package/dist/tools.js +242 -0
  163. package/dist/validate-cli.js +52 -0
  164. package/docs/README.md +58 -0
  165. package/docs/authoring-plain.md +245 -0
  166. package/docs/config.md +353 -0
  167. package/docs/deploy.md +109 -0
  168. package/docs/development.md +75 -0
  169. package/docs/headless.md +148 -0
  170. package/docs/images/how-turri-works.svg +50 -0
  171. package/docs/images/turri-banner.png +0 -0
  172. package/docs/installation.md +118 -0
  173. package/docs/parser.md +108 -0
  174. package/docs/regenerating.md +1116 -0
  175. package/docs/sandbox.md +233 -0
  176. package/docs/skills-and-gates.md +254 -0
  177. package/docs/theming.md +76 -0
  178. package/docs/using.md +454 -0
  179. package/genome/rules/bullet-continuation.md +69 -0
  180. package/genome/rules/concise-specs-examples.md +431 -0
  181. package/genome/rules/concise-specs-integration-examples.md +270 -0
  182. package/genome/rules/concise-specs.md +80 -0
  183. package/genome/rules/definitions.md +107 -0
  184. package/genome/rules/examples/integration-embedded-testing/run_conformance_tests_java.sh +163 -0
  185. package/genome/rules/examples/integration-embedded-testing/run_unittests_java.sh +51 -0
  186. package/genome/rules/exported-concepts.md +39 -0
  187. package/genome/rules/func-specs.md +129 -0
  188. package/genome/rules/impl-reqs.md +68 -0
  189. package/genome/rules/import-modules.md +48 -0
  190. package/genome/rules/integration-embedded-testing.md +276 -0
  191. package/genome/rules/integration-embedded.md +171 -0
  192. package/genome/rules/integration-standalone.md +135 -0
  193. package/genome/rules/integrations.md +137 -0
  194. package/genome/rules/linked-resources.md +69 -0
  195. package/genome/rules/module-structure.md +105 -0
  196. package/genome/rules/project-model.md +88 -0
  197. package/genome/rules/required-concepts.md +44 -0
  198. package/genome/rules/requires-modules.md +80 -0
  199. package/genome/rules/stdlib.md +73 -0
  200. package/genome/rules/test-reqs.md +57 -0
  201. package/genome/skills/add-acceptance-test/SKILL.md +100 -0
  202. package/genome/skills/add-concept/SKILL.md +71 -0
  203. package/genome/skills/add-functional-spec/SKILL.md +84 -0
  204. package/genome/skills/add-functional-specs/SKILL.md +118 -0
  205. package/genome/skills/add-implementation-requirement/SKILL.md +86 -0
  206. package/genome/skills/add-resource/SKILL.md +105 -0
  207. package/genome/skills/add-template/SKILL.md +64 -0
  208. package/genome/skills/add-test-requirement/SKILL.md +73 -0
  209. package/genome/skills/analyze-2-func-specs/SKILL.md +101 -0
  210. package/genome/skills/analyze-func-specs/SKILL.md +123 -0
  211. package/genome/skills/analyze-if-func-spec-too-complex/SKILL.md +211 -0
  212. package/genome/skills/break-down-func-spec/SKILL.md +205 -0
  213. package/genome/skills/brood/SKILL.md +229 -0
  214. package/genome/skills/brood/references/intent.md +35 -0
  215. package/genome/skills/brood/references/product.md +101 -0
  216. package/genome/skills/brood/references/stack.md +61 -0
  217. package/genome/skills/brood/references/testing.md +56 -0
  218. package/genome/skills/bud/SKILL.md +148 -0
  219. package/genome/skills/bud/references/checklist.md +44 -0
  220. package/genome/skills/bud/references/intent.md +30 -0
  221. package/genome/skills/check-plain-env/SKILL.md +285 -0
  222. package/genome/skills/consolidate-concepts/SKILL.md +192 -0
  223. package/genome/skills/create-import-module/SKILL.md +104 -0
  224. package/genome/skills/create-requires-module/SKILL.md +109 -0
  225. package/genome/skills/debug-specs/SKILL.md +188 -0
  226. package/genome/skills/implement-conformance-testing-script/SKILL.md +238 -0
  227. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_cypress.ps1 +337 -0
  228. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_golang.ps1 +111 -0
  229. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +136 -0
  230. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.ps1 +103 -0
  231. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +150 -0
  232. package/genome/skills/implement-unit-testing-script/SKILL.md +160 -0
  233. package/genome/skills/implement-unit-testing-script/assets/run_unittests_flutter.ps1 +87 -0
  234. package/genome/skills/implement-unit-testing-script/assets/run_unittests_golang.ps1 +73 -0
  235. package/genome/skills/implement-unit-testing-script/assets/run_unittests_java.sh +72 -0
  236. package/genome/skills/implement-unit-testing-script/assets/run_unittests_python.ps1 +81 -0
  237. package/genome/skills/implement-unit-testing-script/assets/run_unittests_python.sh +98 -0
  238. package/genome/skills/implement-unit-testing-script/assets/run_unittests_react.ps1 +87 -0
  239. package/genome/skills/init-plain-project/SKILL.md +117 -0
  240. package/genome/skills/init-plain-project/references/checklist.md +30 -0
  241. package/genome/skills/mature/SKILL.md +126 -0
  242. package/genome/skills/refactor-module/SKILL.md +196 -0
  243. package/genome/skills/resolve-section-ownership/SKILL.md +64 -0
  244. package/genome/skills/resolve-spec-conflict/SKILL.md +96 -0
  245. package/genome/skills/spawn/SKILL.md +163 -0
  246. package/package.json +68 -4
  247. package/stdlib/backend/common.plain +25 -0
  248. package/stdlib/backend/conformance/common.plain +12 -0
  249. package/stdlib/backend/conformance/go-gin.plain +9 -0
  250. package/stdlib/backend/conformance/go-nethttp.plain +9 -0
  251. package/stdlib/backend/conformance/java-springboot.plain +9 -0
  252. package/stdlib/backend/conformance/python-django.plain +9 -0
  253. package/stdlib/backend/conformance/python-fastapi.plain +9 -0
  254. package/stdlib/backend/conformance/python-flask.plain +9 -0
  255. package/stdlib/backend/conformance/rust-axum.plain +9 -0
  256. package/stdlib/backend/conformance/typescript-express.plain +9 -0
  257. package/stdlib/backend/conformance/typescript-fastify.plain +9 -0
  258. package/stdlib/backend/conformance/typescript-nestjs.plain +9 -0
  259. package/stdlib/backend/go-gin.plain +18 -0
  260. package/stdlib/backend/go-nethttp.plain +18 -0
  261. package/stdlib/backend/java-springboot.plain +19 -0
  262. package/stdlib/backend/python-django.plain +19 -0
  263. package/stdlib/backend/python-fastapi.plain +23 -0
  264. package/stdlib/backend/python-flask.plain +23 -0
  265. package/stdlib/backend/rust-axum.plain +17 -0
  266. package/stdlib/backend/typescript-express.plain +19 -0
  267. package/stdlib/backend/typescript-fastify.plain +19 -0
  268. package/stdlib/backend/typescript-nestjs.plain +19 -0
  269. package/stdlib/cli/common.plain +17 -0
  270. package/stdlib/cli/conformance/common.plain +11 -0
  271. package/stdlib/cli/conformance/go-cobra.plain +9 -0
  272. package/stdlib/cli/conformance/go-flag.plain +9 -0
  273. package/stdlib/cli/conformance/java-picocli.plain +9 -0
  274. package/stdlib/cli/conformance/python-argparse.plain +9 -0
  275. package/stdlib/cli/conformance/python-click.plain +9 -0
  276. package/stdlib/cli/conformance/python-typer.plain +9 -0
  277. package/stdlib/cli/conformance/rust-clap.plain +9 -0
  278. package/stdlib/cli/conformance/typescript-commander.plain +9 -0
  279. package/stdlib/cli/go-cobra.plain +14 -0
  280. package/stdlib/cli/go-flag.plain +14 -0
  281. package/stdlib/cli/java-picocli.plain +15 -0
  282. package/stdlib/cli/python-argparse.plain +18 -0
  283. package/stdlib/cli/python-click.plain +16 -0
  284. package/stdlib/cli/python-typer.plain +16 -0
  285. package/stdlib/cli/rust-clap.plain +14 -0
  286. package/stdlib/cli/typescript-commander.plain +17 -0
  287. package/stdlib/frontend/angular.plain +17 -0
  288. package/stdlib/frontend/common.plain +17 -0
  289. package/stdlib/frontend/conformance/angular.plain +5 -0
  290. package/stdlib/frontend/conformance/common.plain +11 -0
  291. package/stdlib/frontend/conformance/react-vite.plain +5 -0
  292. package/stdlib/frontend/conformance/sveltekit-spa.plain +5 -0
  293. package/stdlib/frontend/conformance/vue-vite.plain +5 -0
  294. package/stdlib/frontend/react-vite.plain +16 -0
  295. package/stdlib/frontend/sveltekit-spa.plain +16 -0
  296. package/stdlib/frontend/vue-vite.plain +16 -0
  297. package/stdlib/lang/go.plain +13 -0
  298. package/stdlib/lang/java.plain +12 -0
  299. package/stdlib/lang/python.plain +18 -0
  300. package/stdlib/lang/rust.plain +12 -0
  301. package/stdlib/lang/typescript.plain +13 -0
  302. package/stdlib/library/common.plain +15 -0
  303. package/stdlib/library/conformance/common.plain +9 -0
  304. package/stdlib/library/conformance/go.plain +9 -0
  305. package/stdlib/library/conformance/java-gradle.plain +9 -0
  306. package/stdlib/library/conformance/java-maven.plain +9 -0
  307. package/stdlib/library/conformance/python.plain +9 -0
  308. package/stdlib/library/conformance/rust.plain +9 -0
  309. package/stdlib/library/conformance/typescript.plain +9 -0
  310. package/stdlib/library/go.plain +12 -0
  311. package/stdlib/library/java-gradle.plain +13 -0
  312. package/stdlib/library/java-maven.plain +13 -0
  313. package/stdlib/library/python.plain +13 -0
  314. package/stdlib/library/rust.plain +12 -0
  315. package/stdlib/library/typescript.plain +15 -0
package/docs/using.md ADDED
@@ -0,0 +1,454 @@
1
+ # Using turri
2
+
3
+ ## In a conversation
4
+
5
+ ```bash
6
+ cd ~/my-project
7
+ turri
8
+ ```
9
+
10
+ That is pi, with turri's tools, skills and themes loaded - `turri` alone, or with pi's options
11
+ (`turri -c`, `turri --harness-model <m>`). It opens with turri's own
12
+ banner - the jellyfish it is named after, swimming until the conversation fills the screen: a picture in a
13
+ terminal that shows images (Kitty, Ghostty, WezTerm, Warp, iTerm2), and drawn in text in any other, tmux
14
+ included - swimming a stroke a loop, its tentacles following its bell, frames `scripts/jellyfish-frames.mjs`
15
+ writes -
16
+ where commands will run, the rules and skills loaded - rather than pi's startup header
17
+ and resource list; `turri --verbose` shows those too. Talk to it: ask it to start a
18
+ project, add a feature, render a module, fix a spec. It decides which skill or tool applies - but
19
+ not *how* a skill runs: `cultivate` hands the work to the gated runner, which owns the steps, the
20
+ gates and the judges (see [skills and gates](skills-and-gates.md)).
21
+
22
+ The skills that build from scratch:
23
+
24
+ | skill | how it works |
25
+ | --- | --- |
26
+ | `brood` | first, how many questions the stack and product phases may ask - light (3), medium (5), thorough (10) or best judgement, broader with fewer, turri deciding what they leave open; then intent, stack, then testing - conformance tests on or off (into `config.turri.yaml`), their `***test reqs***` and the conformance testing script, which build nothing - then the product feature by feature, where every answer becomes one spec change - a git diff of the `.plain` files, written with `write_spec_diff` and rendered as a render spec diff pulse the moment it is written, with its conformance tests when they are on |
27
+ | `spawn` | its quick twin: asks only what you want to build and which stack - one of the standard library's, your own, or `You choose` - and confirms a five-line brief, then writes the stack and the unit tests itself - conformance tests off, unless you ask for them - and writes the product feature by feature on its own, each feature a spec diff queued as it is written - after which you keep talking, and every change you ask for is a spec diff, and what is left to build is worked out again from the spec |
28
+ | `mature` | for a spec you already have, rough or hand-written: on its own until it is fully rendered - renders what is not built, watches the agents building it, and when one struggles on something the spec leaves open, settles it in the spec as a spec diff, stops that build and renders it again; decides open choices itself and marks them in its report |
29
+
30
+ Peeking is safe while a question is open - a skill's or the chat's: `ctrl+h` opens the side panel over the question,
31
+ which waits under it as it was - the panel says `your question is waiting`, and `ctrl+h` or `esc` takes you back to
32
+ answer it. (The question has the keys, so turri catches `ctrl+h` itself while one is open.) The dialog holds the question
33
+ alone - no hint and no invitation; the `ctrl+h` under the job panel breathes until it is first pressed.
34
+
35
+ While a skill runs, a line above the input shows its phases, every one by name - those done ticked, the one it is in
36
+ marked, the rest to come - and where it is: the skill's name at the left edge, `phase 2 of 4` at the right, and its
37
+ phases centred between them, `✓ intent ━━━━ ⠋ stack ──── ○ testing ──── ○ product`. Under it, dimmed, the phase it is in and what
38
+ it does: `stack - the language, frameworks, storage and architecture`. The phases are the skill's own steps, read from its `SKILL.md`. A skill of one phase, or none, has nothing to be partway through: its line is the spinner and its name alone,
39
+ `⠹ add-test-requirement`.
40
+
41
+ `genome/skills/` holds the rest: adding a feature, a concept, a requirement, a resource; splitting a spec
42
+ that is too big; resolving conflicts; checking the environment - see
43
+ [authoring \*\*\*plain](authoring-plain.md#the-skills). A skill run that is interrupted can be resumed
44
+ where it stopped. A project can have skills of its own, in `.turri/skills/` or `.agents/skills/` - see
45
+ [skills and gates](skills-and-gates.md#a-projects-own-skills).
46
+
47
+ ## The tools
48
+
49
+ | tool | |
50
+ | --- | --- |
51
+ | `regenerate` | regenerate a module and its chain from the spec as it is now - after any change to it, by any means: what is left to regenerate is planned into pulses of one to three functional specs, each with the definitions and reqs it uses, and a pulse regenerating what the spec no longer wants is stopped. With functionalities named, those are regenerated though their spec did not change - rewritten or started over, planned into pulses as any change is; with `from_scratch`, the whole module, its code deleted first - only when you ask, or agree |
52
+ | `drift` | what is left to regenerate: how far the code and its conformance tests have drifted from the spec, starting nothing |
53
+ | `glimpse` | the pulse a module's codebases would start next, and the whole prompt its coding agent would get - starting nothing |
54
+ | `steer` | say how the work is planned - which functional specs go together, what first - for the project or one module, for the session; the next plan follows it, beside what AGENTS.md says under a heading naming the queue |
55
+ | `conform` | write and run conformance tests for functional specs - now, or ahead of their code: every one tested in one conformance pulse, as far as a size guardrail lets (or one a functional spec, or a pulse each of groups you name - 1-3 and 4-6 - when you ask for that), started once every one named is regenerated; whatever the config says |
56
+ | `validate` | validate a spec, regenerating nothing |
57
+ | `engine` | show or choose the model the code is regenerated on - see [below](#choosing-a-model) |
58
+ | `pulses` | the pulses - running, planned and finished - or one of them |
59
+ | `halt` | halt a pulse, or what `activate` started |
60
+ | `diagnose` | why a pulse did not land, from its transcript: how it ended, the stages that went wrong, the last failing test run, the last review, the tool calls that failed |
61
+ | `lineage` | a module's lineage: what each regeneration and conformance run changed in it, and what it was regenerated from |
62
+ | `cultivate` | run a gated skill, its steps and review gates enforced |
63
+ | `release`, `activate` | try what is regenerated: release it to `dist/<module>` and activate it on this machine, installing what it needs - see [deploy](deploy.md) |
64
+ | `ask_user` | put a question to you as a dialog to pick from - several at once, "Something else…" to type, or "Chat about this" to talk it over first; Esc in either goes back to the options |
65
+ | `web_search`, `web_fetch` | search the web and read a page as text - documentation, an API, an error; `curl` and the like run in its `bash` |
66
+
67
+ What each render does, in order, is in [regenerating the code](regenerating.md).
68
+
69
+ The conversation knows the ***plain standard library from its first turn: the stdlib rule in its
70
+ system prompt lists every stack and where the templates are, so "build this as a Flask backend"
71
+ becomes an import of `stdlib/backend/python-flask`, not a stack written out by hand. The banner at
72
+ start says how many stacks there are, and **`/stdlib`** lists them, each with what it is (see
73
+ [the standard library](authoring-plain.md#the-standard-library)).
74
+
75
+ The agent does this work with these tools, never by running turri's command line - or
76
+ another pi - through its shell: that would be a separate, headless run outside regen
77
+ and `/halt`. The harness refuses such a command unless your message asks for the
78
+ command line ("run it headless", "use the CLI", or the command itself). pi configuring itself -
79
+ `pi install`, `update`, `list`, `config`, `auth`, its settings - is not affected.
80
+
81
+ ## Pulses
82
+
83
+ A pulse is one unit of work regenerating the code. It was called a job, and still is where a name is kept -
84
+ `job_id`, `parallel-jobs`, `allow-to-stop-jobs`, `.turri/jobs/` - and in a project's own files written before:
85
+ the chat is told the two are the same, so an `AGENTS.md` or a skill that says "job" needs no change.
86
+
87
+ A render takes minutes, so in the TUI every render tool starts the work as a pulse and
88
+ returns straight away. The conversation carries on; pulses on the same module - or on modules of one
89
+ `requires` chain - queue behind each other, in the order they were asked for, from the first pulse on:
90
+ one queued while the spec is only a scaffold, with no functional specs yet, or while it does not
91
+ parse, still holds its module, so nothing on the module runs beside it. Pulses on modules
92
+ that share nothing run side by side, each with its own progress panel - two
93
+ modules or ten. How many run at once is capped by what the machine has room for: past
94
+ `parallel-jobs` (see [the project config](config.md#how-many-jobs-at-once)), a pulse whose turn has
95
+ come waits for a free slot, and says so.
96
+
97
+ - **The panel** above the input, while something runs, shows on top what finished - a line a module, its
98
+ pulses oldest first, each with its mark (green, red or amber, as in the side panel), number and kind - what
99
+ it regenerated is in the side panel - `cognio … 2 earlier · ✓ 3 regenerate · ✓ 4 conformance`, the newest that fit the width -
100
+ then a rule, and under it each running pulse - `cognio · regenerate pulse 5`, `cognio · conformance pulse 6` - its time and cost, and what its agents are doing. A module whose work is being planned into pulses shows at once,
101
+ before any pulse runs - `shorty · planning the pulses · 12s` - the planner is an agent, and takes a while; a
102
+ `/regenerate` says it began the moment it is sent. Pulses are numbered within their module, as regen numbers
103
+ them. `ctrl+o` expands the agents' trace alone; what finished stays a line a module. The line of keys under
104
+ it - `ctrl+o to expand the trace · ctrl+h to peek at regen` - has each key breathing, fully there to a little
105
+ faint and back, until it is first pressed: once `ctrl+o` has opened the trace, or the side panel has been opened,
106
+ that key is still for the rest of the session and the other breathes on.
107
+ What waits is not in it, and it shows no spec diff - the side panel has both. With nothing running it
108
+ is gone.
109
+ - **A pulse's change** is what its agent works from, not a text diff of the module's file: the items
110
+ `<spec change>` gives the agent - only what the pulse's functional specs use, an import's items as
111
+ well as the module's own, a code pulse's without the test reqs - each in the file it is written in,
112
+ under its section, in the file's order (`change-view.ts`).
113
+ - **A spec diff**, in the side panel, reads as an editor shows a diff: its \*\*\*plain highlighted
114
+ as [plyn](https://github.com/plainlang/plyn) highlights it - section headers, concepts, names in
115
+ backticks, text in quotes, links, the front matter - each added line filled green and each removed one
116
+ red, the text on top, the fill the width of the panel ([colours](theming.md#spec-diffs)). It is shown
117
+ file by file, each file's lines together under its name, with what it adds and takes out - the module
118
+ being rendered first, the rest by name, and none the diff does not change. Each line has its number in
119
+ that file: a spec diff is of the spec as read, with what it imports laid in, so a line is placed in the
120
+ file it is written in - its links read as the parser renders them - and a removed line, in no file now,
121
+ goes with the change it is part of and has no number. A line is never put in a file on a guess: one
122
+ that cannot be placed is listed last, under "not found in the spec's files". Where lines of a file are not in
123
+ the diff, `↕ 28 lines` says how many, as GitHub does - `↑` above the first - and names the section
124
+ the lines under it are in when it is another than the one above, `↕ 28 lines · ***functional specs***`,
125
+ as GitHub names a hunk's function: each section is named once.
126
+ - **The side panel** (`ctrl+h`, as it was left - but on the pulse that last failed, stopped or did not pass, when one has
127
+ since it was last opened: the live panel that showed it is gone with the last pulse, and its announcement in the chat
128
+ says `ctrl+h shows this pulse`; **`/regen`** on regen, **`/pulses`** on the pulses; not `ctrl+j`, which a terminal without the Kitty
129
+ keyboard protocol sends as a line feed, the same as `shift+enter`, and which a dialog takes for
130
+ `enter`; both stay pi's new-line keys. `ctrl+h` is the byte old terminals sent for backspace; a
131
+ terminal set to send `^H` for its Backspace key would open the panel on it) takes the whole screen - the panel or the chat, one at a time.
132
+ It opens on **regen**: the spec itself, in full, with how much of it the code has been regenerated from drawn
133
+ onto it.
134
+
135
+ Every item of the spec - a definition, a req, a functional spec with its sub-bullets and acceptance tests,
136
+ what turri plans and diffs by - is a row in the file's order, its \*\*\*plain highlighted as plyn highlights it
137
+ (as a spec diff is) and wrapped to the width, never cut short. The map has two columns, each headed on the
138
+ line over it with a line of space under it: **status**, a mark a row - its rung on a ladder every item climbs - and the module's file, its
139
+ spec. The top of the panel is where it is seen first: the top line, the module tabs, and the keys - each view's,
140
+ `d talk it through in the chat` first when the module needs you - wrapped, never cut short, a line of space between
141
+ the top line and the keys; then straight under them a rule, a line of space, and the columns' headings. The pulses view has its
142
+ keys at the top too, and a line of space under its rule. The legend is a box of its own in the upper right corner, over what is under it, a line a
143
+ mark, up the ladder. It names every rung, whatever the page shows - to take out only where something is - and a
144
+ panel under 60 columns wide has none.
145
+
146
+ | Mark | Legend | Means |
147
+ | --- | --- | --- |
148
+ | `○` | planned | it differs from the code - planned into a pulse, being planned, or waiting; the top line says which |
149
+ | `⠋` | working | being regenerated now, or being taken out - the spinner in the accent colour |
150
+ | `◇` | regenerated | the code is built from it as it reads now |
151
+ | `⠋` | validating | its conformance tests being written and run - the spinner green, as `◇` and `◆` are |
152
+ | `◆` | conform | regenerated, and its conformance tests pass - its code is shown, end to end, to do what the spec says |
153
+ | `!` | needs you | in the pulse that did not land and halted the module, or the planner found no plan |
154
+ | `−` | to take out | taken out of the spec, still in the code - a struck-through red ghost, with the code record's text, until the pulse that takes it out lands |
155
+
156
+ `◇` and `◆` are both green, and mean the same whatever `conformance-tests:` says: a functional spec regenerated
157
+ and not conformed is `◇` with its conformance tests on, off or not chosen, so changing the setting changes no mark.
158
+ Tests written for an earlier text leave it at `◇`. Definitions and reqs are never conformed: `◇` is as far as they go.
159
+ Test reqs are shown only where conformance tests are on - `conformance-tests:` is not `false`, or `conform` turned
160
+ them on this session. A test req is the conformance tests', never built into the code: `◆` once they follow it
161
+ as it reads now, the green `⠋` while a conformance pulse writes them for it, `○` until then - and no mark where no
162
+ conformance test is written at all. No pulse numbers are drawn in the gutter - they move whenever the plan is
163
+ made again; `p` on an item goes to the pulse that brings it.
164
+
165
+ **Needs you.** The top line ends `! needs you`, in red, and under the first `!` of the module is what for, and
166
+ how: `needs you - pulse 3 didn't land - its unit tests never passed · d to talk it through in the chat`. `d` closes
167
+ the panel and asks the chat, in your words, what went wrong and what to do about it, with turri's reason for
168
+ the halt; the chat works it out with you - a diagnosis, a change to the spec, the machine set up - and
169
+ regenerates. Pulses are numbered as they start in a module, from 1 each session.
170
+
171
+ A changed item shows what changed in it: its first line word by word - what is gone struck through in red,
172
+ what is new in green, what is kept highlighted as it reads now - and, under it, only the sub-bullets that changed. A spec never built that is taken
173
+ out is simply gone. The top line has a strip of the module's functional specs - built, regenerating, planned,
174
+ waiting - and how many are built, then what is happening: `pulse 3 of 8 regenerating`, or why nothing is -
175
+ `not asked to build - regenerate plans it` (turri was just opened, or nothing has asked for the module: the
176
+ plan lives in memory and is made again on the next regeneration), `planning`, `waits for backend`, or
177
+ `! needs you`. `enter` opens an item: all of
178
+ its text against the code's, and its acceptance tests. Where it stands is beside its mark, and is not said again
179
+ under it.
180
+
181
+ One module is shown at a time, with a tab for each module of the chain on the line under the top line, in
182
+ the chain's order - the module it is built on to the left: `d365_version_api [d365_http_client] d365_utils
183
+ 12 ›`. A tab regenerating spins, one stuck says `!`; what does not fit is counted at either end. `←` `→` go from
184
+ one tab to the next. The module shown is the one in focus - the one regenerating now, else the one asked for,
185
+ else the first - until you pick another tab; it goes back to following once another module is in focus, or
186
+ the one in focus starts regenerating. Under the module's own text is what it imports, under **imported**, a
187
+ folded block a file, `▸ from stdlib/backend/python-fastapi · 7 reqs · all built`, closed until opened. The
188
+ modules it requires are tabs of their own: a chain of many modules is never drawn nested, one in the next.
189
+ A map longer than the screen has a minimap down its right edge, a cell a slice in the colour of
190
+ its most pressing mark, the slice shown solid. The map is read from the files - the code record, the
191
+ `.plain` files, the tests record - so it is right the moment turri opens a project, before anything runs;
192
+ the work loop's plan adds the pulses on top. It maps the files asked to build this conversation, else
193
+ `module:` in `config.turri.yaml`, else the `.plain` files of the folder that no other one there imports or
194
+ requires - the folder's files looked at again only once one of them, or its config, changes. `↑` `↓` move
195
+ row by row, `enter` or `space` open and close an item or an import block - a functional spec opens to its
196
+ sub-bullets and its `***acceptance tests***`, nested under it as the spec has them - `←` `→` go to the next module's
197
+ tab, `o` and `c` open or close everything shown, `pgup` `pgdn` and the
198
+ wheel scroll, `g`/`G` go to the top and the bottom.
199
+
200
+ `p` goes to the **pulses** - and back - onto the pulse that regenerates the item under the cursor, and
201
+ back onto the first item the pulse under the cursor regenerates. The pulses are every pulse as three sections - running, queued, finished - each opened and closed on
202
+ its own (running and queued start open). A pulse is one line: its module, kind and number (`hubspot · regenerate pulse 1`, `hubspot · conformance pulse 2`) - so it is named wherever a pulse is named in a line (the job panel, the `pulses` tool, `/halt`, the command line), never by what it regenerates, which is in it, opened - its time (none while it is queued: it has not started) and its cost - a
203
+ finished one's mark green when it passed, red when it failed or did not pass, amber when it was stopped.
204
+ Opened, a running one shows what it is doing; a queued one, what it waits for; a finished one, its agents
205
+ and what each spent, and whether it did not pass. Under it is a row
206
+ for each file its spec diff changes - the file of the module being rendered first and open, the rest by
207
+ name and closed - each opening onto that file's lines. A file with nothing added or taken out is not
208
+ listed. `↑` `↓` move, `enter` or `space` open and close what is under the cursor, `→` `←` open and close
209
+ (`←` on a closed pulse goes to its section, on a closed file to its pulse), `o` and `c` open or close every
210
+ pulse of the section - or, on a file, every file of its pulse - `pgup` `pgdn` and the wheel scroll, `g`/`G`
211
+ go to the top and the bottom. The cursor stays on its row when the pulse under it moves on; a pulse opened
212
+ closes when it moves to another section. What is open is kept while the panel is closed. What the agents
213
+ said and did is not shown - it is in each pulse's log (see [Agent logs](#agent-logs)).
214
+
215
+ `ctrl+h` again, or `esc`, closes it and goes back to the chat. While it shows, every key is the panel's,
216
+ whatever else happens: a question the chat model asks in the background (`ask_user`) waits in the chat,
217
+ unanswered - an `enter` in the panel never answers it - and the panel's top line says "the chat is waiting
218
+ for your answer". Back in the chat, the question is there, with the keys.
219
+ - `turri` runs pi in fullscreen mode, so the conversation stays where you scroll it while
220
+ the pulses redraw (PgUp/PgDn, the wheel); `--tui-mode regular` goes back to the terminal's own
221
+ scrollback.
222
+ - **`/turri-config`** changes a setting of the project's `config.turri.yaml` - the models, review, conformance tests, any
223
+ key - and says when it takes effect: now, at your next message, or at the next pulse; never only after a restart.
224
+ See [changing it from the chat](config.md#changing-it-from-the-chat).
225
+ - **`/stack`** chooses the stack everything is built with from then on, in a project whose parts are on different
226
+ stacks: a list of the project's stacks, or `/stack backend`, `/stack none`. The stack's `config.turri.<stack>.yaml`
227
+ is laid over `config.turri.yaml` - its testing scripts, toolchains, models - for the session; a pulse already
228
+ running keeps the stack it started with. The chat model switches it too when you ask. See
229
+ [stacks](config.md#stacks).
230
+ - **`/regenerate [module | file.plain] [functionality ...] [from scratch] [how to cut the work]`** regenerates a module from its spec as it is now, as
231
+ the `regenerate` tool does: what is left to regenerate is planned into pulses - one functional spec at a time, a few
232
+ together or the whole module in one, as the planner judges - and the first starts. Words after the module are
233
+ guidance for that plan (`/regenerate app models first`). A module's name typed with spaces for its underscores is
234
+ that module - `/regenerate d365_function executor` is `d365_function_executor`. With no module named: the one `module:` in
235
+ `config.turri.yaml` names, else the folder's top modules, to pick from. Asked for from scratch - `from scratch`,
236
+ `start over`, `delete the module` - it asks first, then deletes the module's code and conformance tests in every
237
+ codebase where they live, committed so `/lineage` keeps them, and regenerates the whole module from its spec,
238
+ built though nothing in it changed: `/regenerate shorty from scratch`. The chat's `regenerate` does the same with
239
+ `from_scratch`, when you ask for it; `turri regenerate --from-scratch` on the command line, not with `--dry-run`.
240
+ Functionalities named after the module - `/regenerate shorty 3 5` - are regenerated though their spec did not
241
+ change, on the model chosen for functionalities: as `turri regenerate shorty.plain 3 5` does, and the chat's
242
+ `regenerate` with `functionalities`.
243
+ - **`/halt <id>`** halts a pulse - a queued one never starts - and **`/halt activated <name>`** halts a
244
+ server `activate` started; it lists both when no id is given.
245
+ - **What these commands show you, the chat knows.** What `/regenerate` and `/halt activated` tell you - a spec that
246
+ does not parse, the pulses planned, a server halted - stays in the chat under the command, and since a slash command
247
+ runs outside the conversation, it is put in the conversation as well: say "fix it" next and turri knows what you are
248
+ looking at. A halted pulse reaches it as every pulse's end does.
249
+ - **Nothing is queued.** What is left to build is worked out from what each codebase is built from
250
+ and the spec as it is now - again whenever a pulse ends or the spec changes - and the first pulse of
251
+ it runs; see [a whole module](regenerating.md#a-whole-module). Changes that overlap never pile up: the next pulse
252
+ builds the spec as it is. The pulses planned after the one running are listed behind it, as queued,
253
+ and so is each module waiting for the one it is built on - "waits for base" - until it can be planned.
254
+ A change inside what the running pulse regenerates - a spec it regenerates reworded or given a sub-bullet, a definition or req it is given, a file they link - steers it: its agent is told, and it lands the spec as it is now there, twice a pulse at most. Otherwise a pulse building something the spec no longer wants is stopped and rolled back - unless `allow-to-stop-jobs: false` in `config.turri.yaml`, which has it land first and the change regenerated on top. To drop something, take it out of the spec - one spec diff. Stopping a pulse leaves its change
255
+ in the spec: the codebase waits until the spec changes or it is asked for again.
256
+ - **A change to a module below** is made in the codebase at the tip of the chain, where its code
257
+ lives; the codebase below is left as it was, and is brought up to its own spec only when a new
258
+ module is to start from it. Specs moved into a module the code was not built on stop the codebase:
259
+ no change to its code brings that module in, so it has to be started over - its code and
260
+ conformance tests taken out, kept in its history, and built again from the bottom of the chain.
261
+ That is never done unasked: the chat asks you, saying why, and regenerates it from scratch once you agree;
262
+ on the command line `turri regenerate` asks at the terminal, and `--start-over` agrees in advance.
263
+ - **Conformance tests are a track of their own.** A code pulse lands once its unit tests pass and are
264
+ reviewed. Then, before the next one builds on it, a conformance pulse writes and runs the tests of what it
265
+ built - from the test reqs and acceptance tests - with the whole suite the module inherits, and, where one
266
+ fails, fixes the test or the code, whichever is wrong; what they are written for is recorded in
267
+ `tests/.turri.json`. With `conformance-tests: false` none is written until you ask -
268
+ `conform`, for a module or some of its functional specs. A conformance pulse that does not pass
269
+ is undone whole and halts the conformance tests alone: the code goes on being built.
270
+ - **A pulse that fails** - its work errors, or it does not pass - is run once more. Failing again, it
271
+ stops, and so does every pulse queued behind it on the same module, without running - the other
272
+ modules' pulses go on. The harness then works out why: an
273
+ agent that can read the project's specs, code, tests, testing scripts and logs, and turri's
274
+ own source, skills and rules, says what happened, why, whether the fix belongs in the spec, the
275
+ environment, the code or turri itself, and exactly what to do.
276
+ - **When a pulse finishes** the transcript shows its line - `✓`, `✗` or `■`, its module, kind and number,
277
+ how long it took and what it cost, never what it regenerated -
278
+ `✓ shorty · conformance pulse 4 finished after 3m 47s · 488.6k tok · $0.02` - and the chat, which
279
+ gets its whole report, reacts then and there, whatever else is running or queued, without waiting
280
+ for you to speak: at once when it is idle, else as soon as the reply it is in ends. It does what the
281
+ project's guidance says to do when a pulse finishes - release what was built, say - or tells you
282
+ what finished and what it means. Ask to try it ("let me try it") and the chat releases what is
283
+ built to `dist/<module>` and starts it on your machine, even while other pulses run. See [deploy](deploy.md). The chat reacts to it then and there,
284
+ whatever else is running or queued, without waiting for you to speak - at once when it is idle, else
285
+ as soon as the reply it is in ends: it does what the project's guidance says to do when a pulse
286
+ finishes (release what was built, say), or tells you in a line or two what finished.
287
+ - **When a pulse stops** - a gate still failing after 20 attempts - it says where it stopped, why in
288
+ plain words, and what to change in the spec - which section, and how.
289
+ Running the same build again picks up from there.
290
+
291
+ In `print`, `json` and `rpc` modes the process ends when the answer is written, so the tools wait
292
+ for the work there instead. Pulses live in memory for the session; the work itself is on disk.
293
+
294
+ ## The project's config.turri.yaml
295
+
296
+ The chat reads the project's `config.turri.yaml` afresh every turn and follows it: its agent is told what
297
+ it sets, and the render tools default to it - `module` when you ask to build without naming one,
298
+ `conformance-tests: false` to render without conformance tests (none written, none of the existing
299
+ ones run) unless you ask for them, `coding-model` for what renders run on, and the testing scripts.
300
+ `harness-model` is what `turri` starts on. What you ask for in the conversation wins.
301
+ Every key, what happens without it, and how the models inherit: [the project config](config.md).
302
+
303
+ A project whose parts are on different stacks gives each stack its own `config.turri.<stack>.yaml`
304
+ beside `config.turri.yaml` - `config.turri.backend.yaml`, `config.turri.frontend.yaml` - with its
305
+ testing scripts, models and conformance over the project's. A stack is chosen, never worked out:
306
+ `/stack backend` before building the backend, `/stack frontend` before the frontend, and every render
307
+ from then on follows the chosen one's; the chat is told each stack's and which is chosen, and the status
308
+ bar shows it. See [stacks](config.md#stacks).
309
+
310
+ A project with only a `config.yaml` - turri's file before it had its own name, or another tool's - is
311
+ read from it until turri first writes a setting, which copies it to `config.turri.yaml`; see
312
+ [the old config.yaml](config.md#the-old-configyaml).
313
+
314
+ ## Choosing a model
315
+
316
+ There are three: the **harness model**, the one you chat with; the **coding model**, the one
317
+ every render runs on - functionalities, conformance tests, repairs, spec changes; and the **judge
318
+ model**, which gives the verdicts in a conformance run - the judge, which says whether the code, the
319
+ tests or the spec is wrong, and the test review. The project's `config.turri.yaml` can give each a model and
320
+ a thinking level (off, minimal, low, medium, high, xhigh, max):
321
+
322
+ ```yaml
323
+ harness-model:
324
+ model: anthropic/claude-opus-5-5
325
+ thinking: high
326
+ coding-model:
327
+ model: amazon-bedrock/eu.anthropic.claude-sonnet-5
328
+ thinking: medium
329
+ judge-model:
330
+ model: anthropic/claude-opus-5-5
331
+ ```
332
+
333
+ Each may leave out either part, and a bare string (`coding-model: provider/id`, or
334
+ `provider/id:high`) is a model alone. What one leaves out it takes from the one it inherits from:
335
+ the judge model from the coding model, the coding model from the harness model - so with only a
336
+ harness model, everything runs on it.
337
+
338
+ On the command line, `turri --harness-model <m> --coding-model <m>` wins over them
339
+ (pi's own `--model` works for the harness model too), and in the conversation pi's `/model`
340
+ changes the harness model and `engine`, below, the coding model. `model:`, from before
341
+ there were two, is read as `coding-model`. With neither, renders run on the conversation's model.
342
+
343
+ Every render runs on the coding model unless you say otherwise. Say it in words -
344
+ "render spec changes with gpt 5.5", "build the functionalities on Gemini 3.6 Flash", "use Claude
345
+ for everything" - and the agent calls `engine`, which holds for the rest of the session
346
+ (a resumed one too):
347
+
348
+ | kind of work | covers |
349
+ | --- | --- |
350
+ | spec changes | render spec diff pulses, including the ones `brood` queues as you answer |
351
+ | functionalities | render functionality, render module, regenerate, conformance |
352
+ | everything | both |
353
+
354
+ It works mid-interview as well: the skill's agent has the same tool. Pulses already queued keep the
355
+ model they were queued with; `"chat"` drops the session's choice, back to the default coding model -
356
+ `--coding-model`, `config.turri.yaml`, or the conversation's. `/engine` shows
357
+ what each kind of work runs on. A render tool can also be given a model for one call.
358
+
359
+ Names are resolved strictly, because pi's own matching guesses and says nothing ("gpt-5" can land
360
+ on a Bedrock model you have no key for). An exact `provider/model-id` is taken as it is. A looser
361
+ name is taken when it fits exactly one model you have credentials for, or is exactly one model's
362
+ id in other words ("gpt 5.5" is `openai/gpt-5.5`, not `gpt-5.5-pro`). Anything else comes back as
363
+ a short list and the agent asks you which one; a model whose provider has no credentials is never
364
+ picked.
365
+
366
+ A provider a pi extension registers - your company's own LLM gateway, say - works for every agent
367
+ the conversation starts, not only for the conversation. Those agents load no extensions (they would
368
+ load a second copy of turri), so each is given the providers the conversation's extensions
369
+ registered, as they are when it starts. An unattended run - `turri regenerate`, `render` and the
370
+ rest, outside the chat - has no conversation to take them from: there, only the providers in pi's
371
+ own configuration (`~/.pi/agent/models.json` and `auth.json`) are there, so a gateway those runs use
372
+ has to be set up in `models.json`.
373
+
374
+ To change pi's own default, in `~/.pi/agent/settings.json`:
375
+
376
+ ```json
377
+ { "defaultProvider": "google", "defaultModel": "gemini-3.1-pro-preview" }
378
+ ```
379
+
380
+ A provider failure - no credits, bad key, rate limit - is raised with the provider's own message,
381
+ rather than surfacing as an agent that said nothing.
382
+
383
+ ## Module history
384
+
385
+ Each `plain_modules/<module>` is a git repository whose git directory is `.plaingit` rather than
386
+ `.git`, so it stays plain files to your own repository. A commit is made after every step that
387
+ changes the module - a render, a functionality regenerated, a conformance run, a regression repair, a spec
388
+ change. `/lineage [module]` and `lineage` show it.
389
+
390
+ The last commit is also the last known good state. Every render, functionality regenerated, spec change and
391
+ conformance run starts by putting the codebase it works in back to it, so if turri was
392
+ stopped or restarted mid-pulse, whatever that pulse left half-written is undone first - and one that
393
+ does not pass is undone the same way when it ends, commits and all. Only work that passed is
394
+ committed. Installed dependencies and caches are not in the history and stay. With git directly:
395
+
396
+ ```bash
397
+ git --git-dir=plain_modules/<module>/.plaingit --work-tree=plain_modules/<module> log
398
+ ```
399
+
400
+ ## Agent logs
401
+
402
+ When an agent does something you cannot explain, its logs are where to look: the chat shows what
403
+ its pulse is doing, not what its agents said. Every agent a render starts - the
404
+ coding agent, the conformance agent, the repair agent, the spec-steps planner - also streams its
405
+ whole conversation to a file of its own, always.
406
+
407
+ The logs are in `.turri/debug/` in the project, beside `plain_modules`, one per agent, named
408
+ by when it started and what it is: `2026-09-26T13-45-02-123Z-app-3-coding-agent.log`. Each starts
409
+ with the pulse it runs for, its model and thinking level, its folder, its saved pi session, its
410
+ tools and its system prompt, and then has, in order and stamped with the time: every prompt it is
411
+ sent, whole; its thinking and replies as they stream; every tool call with its arguments, numbered
412
+ - `→ #3 bash` - and its whole result under the same number, `← #3 bash done`, since calls made
413
+ together run at once and finish in any order; a tool call a response was cut off in, marked as
414
+ never run; each response's stop reason, tokens and cost; the provider's
415
+ retries and errors; and how each turn ended. Every line is on disk as it happens, so
416
+ `tail -f` follows an agent live and a run that crashed leaves its log up to that moment. The pulse's
417
+ own log names each agent's log as it starts.
418
+
419
+ Beside them, each pulse has a log of its own in `.turri/jobs/` - `<time>-<pulse id>-<kind>.log`:
420
+ its whole transcript, written as it happens. The harness's stages, the functional spec or the
421
+ diff it builds, and every one of its agents in turn - each prompt, its thinking and replies, every
422
+ tool call and its result, whole where the screen clips them - and how the pulse ended. A finished pulse,
423
+ opened in the side panel, names it. It is the one to read for a pulse as a whole; an agent's own log has its system
424
+ prompt, tokens and retries besides.
425
+
426
+ No agent can read the logs: they are outside `plain_modules` - or, for a `--build-dir` outside it,
427
+ beside that folder rather than in it. Nothing prunes them either - delete
428
+ the folder when you are done with it. A log that cannot be written is given up on without failing
429
+ the render.
430
+
431
+ ## From the command line
432
+
433
+ The same work, without a conversation. Run it from the directory that holds the spec, so its
434
+ linked resources resolve the way the parser expects. For a long run - a whole spec overnight - see
435
+ [running unattended](headless.md).
436
+
437
+ ```bash
438
+ turri validate <file.plain> # validate a spec - no model, no API key
439
+ turri drift <file.plain> # what is left to regenerate - no model, starts nothing
440
+ turri regenerate <file.plain> # regenerate what the code is not built from yet, and what it requires
441
+ turri glimpse <file.plain> # plan it, and print the first job's prompt - starts nothing
442
+ turri regenerate <file.plain> 2 # regenerate functionality 2 again, changed or not
443
+ turri regenerate <file.plain> --from-scratch # delete the module's code and tests (its lineage keeps them), regenerate all of it
444
+ turri spec-diff <file.plain> <diff> # apply a spec diff, and regenerate it
445
+ turri conform <file.plain> 1 # black-box tests for functionality 1
446
+ turri lineage <module> # what each regeneration changed in a module, and when
447
+ turri cultivate brood # run a skill directly - by name, the project's too, or by its folder
448
+ turri release <file.plain> # release what is regenerated to dist/<module>, and activate it here
449
+ ```
450
+
451
+ The ones that build take `--model provider/model-id`; `regenerate` also takes `--build-dir` and
452
+ `--dry-run`, which plans the work, prints the prompt of each codebase's first pulse and starts nothing.
453
+ Template directories come from `PLAIN_TEMPLATE_DIRS`. `--help`
454
+ on any of them lists the rest.
@@ -0,0 +1,69 @@
1
+ ---
2
+ description: Bullet and continuation syntax for every section in .plain files
3
+ ---
4
+
5
+ # Rules for bullets and continuations in `.plain` files
6
+
7
+ These rules apply to every section and to concept explanations.
8
+
9
+ ## No line-length limit
10
+
11
+ - `.plain` does not impose a maximum number of characters per line
12
+ - Do not split a valid line merely to satisfy an arbitrary formatting width
13
+ - Prefer clear, precise wording; concision must never remove required detail
14
+ - Length is bounded by content, not by width: say everything required, in the fewest plain words that stay exact (see `concise-specs.md`)
15
+
16
+ ## One statement per line
17
+
18
+ This is the preferred `.plain` authoring convention, not something the renderer enforces. A line
19
+ break in a section means one of exactly two things: a new `- ` statement, or a nested `- `
20
+ clarification of the statement above it. There is no third, typographic reason to break a line.
21
+
22
+ - Write each statement on a single line, however long
23
+ - Never break a line just for width: a bare continuation (an indented line without `- `) adds a
24
+ line break that carries no structure — to every future reader and editing agent it is
25
+ indistinguishable from a deliberate sub-point
26
+ - The test: if content deserves its own line, it deserves its own `- ` bullet; if it doesn't,
27
+ keep it on the parent's line
28
+ - What the renderer does enforce is the top level: every statement in a section must be a `- `
29
+ list item — a flush-left prose line is a syntax error. A bare continuation, by contrast, is
30
+ accepted and folded into its parent item verbatim
31
+
32
+ BAD — line broken for width (bare continuation):
33
+
34
+ ```plain
35
+ ***functional specs***
36
+
37
+ - :GatewayWebhook: hands off :StripeRequest: to :StripeIntegration:.handle(),
38
+ which returns a list of :EventEnvelope: dicts conforming to the gateway contract.
39
+ ```
40
+
41
+ GOOD — one valid list item:
42
+
43
+ ```plain
44
+ ***functional specs***
45
+
46
+ - :GatewayWebhook: hands off :StripeRequest: to :StripeIntegration:.handle(), which returns a list of :EventEnvelope: dicts conforming to the gateway contract.
47
+ ```
48
+
49
+ BEST — separate clarifications expressed as nested bullets:
50
+
51
+ ```plain
52
+ ***functional specs***
53
+
54
+ - :GatewayWebhook: hands off :StripeRequest: to :StripeIntegration:.handle().
55
+ - The method returns a list of :EventEnvelope: dicts.
56
+ - The dicts conform to the gateway's :EventEnvelope: contract.
57
+ ```
58
+
59
+ ## Presenting `.plain` examples
60
+
61
+ - Show every example under its owning section header
62
+ - Separate top-level list items with one blank line
63
+ - Keep nested clarifications directly under their parent without a blank line
64
+ - BAD, WRONG, `Before:`, and `Too complex:` examples may intentionally demonstrate invalid syntax
65
+
66
+ ## Content that belongs in resources
67
+
68
+ Long URLs, schema fragments, and example payloads belong in `resources/` because they are external
69
+ artifacts, not because of their character count. Follow `linked-resources.md`.