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

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 (103) hide show
  1. package/.pi/themes/turri-dark.json +67 -66
  2. package/.pi/themes/turri-light.json +71 -73
  3. package/README.md +40 -128
  4. package/assets/jellyfish/dark-00.png +0 -0
  5. package/assets/jellyfish/dark-01.png +0 -0
  6. package/assets/jellyfish/dark-02.png +0 -0
  7. package/assets/jellyfish/dark-03.png +0 -0
  8. package/assets/jellyfish/dark-04.png +0 -0
  9. package/assets/jellyfish/dark-05.png +0 -0
  10. package/assets/jellyfish/dark-06.png +0 -0
  11. package/assets/jellyfish/dark-07.png +0 -0
  12. package/assets/jellyfish/dark-08.png +0 -0
  13. package/assets/jellyfish/dark-09.png +0 -0
  14. package/assets/jellyfish/dark-10.png +0 -0
  15. package/assets/jellyfish/dark-11.png +0 -0
  16. package/assets/jellyfish/light-00.png +0 -0
  17. package/assets/jellyfish/light-01.png +0 -0
  18. package/assets/jellyfish/light-02.png +0 -0
  19. package/assets/jellyfish/light-03.png +0 -0
  20. package/assets/jellyfish/light-04.png +0 -0
  21. package/assets/jellyfish/light-05.png +0 -0
  22. package/assets/jellyfish/light-06.png +0 -0
  23. package/assets/jellyfish/light-07.png +0 -0
  24. package/assets/jellyfish/light-08.png +0 -0
  25. package/assets/jellyfish/light-09.png +0 -0
  26. package/assets/jellyfish/light-10.png +0 -0
  27. package/assets/jellyfish/light-11.png +0 -0
  28. package/dist/ask.js +34 -15
  29. package/dist/brand.js +7 -7
  30. package/dist/cli-options.js +12 -6
  31. package/dist/config-edit.js +1 -0
  32. package/dist/config.js +5 -2
  33. package/dist/cultivate-cli.js +16 -23
  34. package/dist/extension.js +59 -67
  35. package/dist/init-config.js +5 -0
  36. package/dist/jellyfish.js +130 -0
  37. package/dist/loop-cli.js +19 -7
  38. package/dist/loop-tools.js +11 -5
  39. package/dist/module-report.js +5 -4
  40. package/dist/pi.js +76 -19
  41. package/dist/question-dialog.js +1 -0
  42. package/dist/regenerate/activity.js +21 -0
  43. package/dist/regenerate/list-arguments.js +121 -0
  44. package/dist/regenerate/loop.js +21 -8
  45. package/dist/regenerate/plain-palette.js +52 -37
  46. package/dist/regenerate/regenerate.js +4 -2
  47. package/dist/regenerate/self-check.js +13 -6
  48. package/dist/regenerate/side-panel.js +1 -1
  49. package/dist/regenerate/spec-map-view.js +9 -5
  50. package/dist/regenerate/test-scripts.js +54 -10
  51. package/dist/regenerate/unit-review.js +1 -1
  52. package/dist/regenerate-cli.js +11 -5
  53. package/dist/release-cli.js +3 -8
  54. package/dist/review/live.js +2 -1
  55. package/dist/run-report.js +39 -1
  56. package/dist/validate-cli.js +3 -8
  57. package/docs/README.md +5 -12
  58. package/docs/authoring-plain.md +37 -119
  59. package/docs/config.md +53 -178
  60. package/docs/deploy.md +21 -80
  61. package/docs/development.md +13 -41
  62. package/docs/headless.md +45 -121
  63. package/docs/images/how-turri-works.svg +29 -31
  64. package/docs/images/turri-banner.png +0 -0
  65. package/docs/installation.md +13 -40
  66. package/docs/parser.md +15 -43
  67. package/docs/regenerating.md +229 -938
  68. package/docs/sandbox.md +38 -152
  69. package/docs/skills-and-gates.md +50 -171
  70. package/docs/theming.md +45 -46
  71. package/docs/using.md +69 -345
  72. package/genome/rules/bullet-continuation.md +5 -13
  73. package/genome/rules/concise-specs-examples.md +2 -4
  74. package/genome/rules/concise-specs-integration-examples.md +2 -6
  75. package/genome/rules/concise-specs.md +1 -2
  76. package/genome/rules/func-specs.md +1 -0
  77. package/genome/rules/integration-embedded-testing.md +1 -4
  78. package/genome/rules/integrations.md +1 -2
  79. package/genome/rules/project-model.md +14 -35
  80. package/genome/rules/stdlib.md +14 -49
  81. package/genome/rules/turri-regeneration.md +48 -0
  82. package/genome/skills/add-implementation-requirement/SKILL.md +1 -2
  83. package/genome/skills/analyze-if-func-spec-too-complex/SKILL.md +3 -8
  84. package/genome/skills/brood/SKILL.md +37 -127
  85. package/genome/skills/brood/references/intent.md +4 -12
  86. package/genome/skills/brood/references/product.md +24 -76
  87. package/genome/skills/brood/references/stack.md +7 -29
  88. package/genome/skills/brood/references/testing.md +11 -42
  89. package/genome/skills/bud/SKILL.md +32 -109
  90. package/genome/skills/bud/references/intent.md +4 -11
  91. package/genome/skills/implement-conformance-testing-script/SKILL.md +3 -6
  92. package/genome/skills/implement-unit-testing-script/SKILL.md +1 -2
  93. package/genome/skills/mature/SKILL.md +21 -69
  94. package/genome/skills/refactor-module/SKILL.md +24 -2
  95. package/genome/skills/spawn/SKILL.md +28 -113
  96. package/package.json +1 -1
  97. package/assets/jellyfish/dark-12.png +0 -0
  98. package/assets/jellyfish/dark-13.png +0 -0
  99. package/assets/jellyfish/dark-14.png +0 -0
  100. package/assets/jellyfish/fallback.txt +0 -252
  101. package/assets/jellyfish/light-12.png +0 -0
  102. package/assets/jellyfish/light-13.png +0 -0
  103. package/assets/jellyfish/light-14.png +0 -0
@@ -79,7 +79,8 @@ export function createLiveReviewer(opts) {
79
79
  pending.push(finding);
80
80
  all.push(finding);
81
81
  }
82
- if (violations.length === 0) {
82
+ // No verdict - its turn stopped before it gave one - clears nothing: the scope is looked at again next pass.
83
+ if (captured !== undefined && violations.length === 0) {
83
84
  cleared.push(scope);
84
85
  }
85
86
  else if (captured?.question) {
@@ -22,6 +22,9 @@ const emptyTotals = () => ({
22
22
  llm_calls: 0,
23
23
  agent_turns: 0,
24
24
  compactions: 0,
25
+ provider_retries: 0,
26
+ provider_stalls: 0,
27
+ turns_stopped: 0,
25
28
  model_seconds: 0,
26
29
  });
27
30
  function addUsage(totals, usage) {
@@ -43,8 +46,14 @@ function addEvent(totals, event, tokens) {
43
46
  }
44
47
  else if (event.kind === "turn")
45
48
  totals.agent_turns += 1;
46
- else
49
+ else if (event.kind === "compaction")
47
50
  totals.compactions += 1;
51
+ else if (event.kind === "provider_retry")
52
+ totals.provider_retries += 1;
53
+ else if (event.kind === "provider_stall")
54
+ totals.provider_stalls += 1;
55
+ else
56
+ totals.turns_stopped += 1;
48
57
  }
49
58
  function sumTotals(a, b) {
50
59
  const sum = emptyTotals();
@@ -181,6 +190,32 @@ export function startRunReport(options) {
181
190
  list,
182
191
  };
183
192
  };
193
+ /** The spec gaps the pulses' agents met, in the order the pulses started: questions a person would want to decide. */
194
+ const specGapsOf = (jobs) => jobs.flatMap((job) => {
195
+ const details = job.details;
196
+ return (details?.specGaps ?? []).map((gap) => ({
197
+ module: job.module ?? null,
198
+ pulse: job.pulse ?? null,
199
+ pulse_id: job.id,
200
+ landed: job.status === "succeeded" && details?.landed === true,
201
+ question: gap.question,
202
+ assumption: gap.assumption,
203
+ }));
204
+ });
205
+ /** Each request the provider failed and was waited out or stalled on, and each turn turri ended itself: why, and where. */
206
+ const turnIncidentsOf = () => events
207
+ .filter((event) => event.kind === "provider_retry" || event.kind === "provider_stall" || event.kind === "stopped")
208
+ .map((event) => ({
209
+ kind: event.kind,
210
+ pulse_id: event.job ?? null,
211
+ role: event.role ?? null,
212
+ model: event.model ?? null,
213
+ ...(event.kind === "stopped"
214
+ ? { reason: event.reason ?? null }
215
+ : event.kind === "provider_stall"
216
+ ? { silent_seconds: Math.round((event.waitMs ?? 0) / 1000) }
217
+ : { error: event.error ?? null, attempt: event.attempt ?? null, of: event.of ?? null, wait_seconds: Math.round((event.waitMs ?? 0) / 100) / 10 }),
218
+ }));
184
219
  const functionalitiesOf = (counts) => {
185
220
  if (counts === undefined)
186
221
  return null;
@@ -228,6 +263,7 @@ export function startRunReport(options) {
228
263
  build_dir: options.buildDir !== undefined ? resolve(options.buildDir) : null,
229
264
  conformance_tests: options.conformanceTests,
230
265
  review: options.review ?? null,
266
+ mutation_testing: options.mutationTesting ?? null,
231
267
  models: {
232
268
  ...Object.fromEntries(Object.entries(options.models).map(([role, choice]) => [role, { model: choice.model ?? null, thinking: choice.thinking ?? null }])),
233
269
  observed: Object.fromEntries([...new Set(events.map((event) => event.role ?? "unknown"))].sort().map((role) => [role, [...new Set(events.filter((event) => (event.role ?? "unknown") === role).map((event) => event.model ?? "unknown"))].sort()])),
@@ -245,6 +281,8 @@ export function startRunReport(options) {
245
281
  usage: usageOf(jobs),
246
282
  pulses: pulsesOf(jobs, now),
247
283
  functionalities: functionalitiesOf(attempt(sources.completion)),
284
+ spec_gaps: specGapsOf(jobs),
285
+ turn_incidents: turnIncidentsOf(),
248
286
  ...(exitParts ?? {}),
249
287
  logs: {
250
288
  jobs_dir: fromProject(join(projectRoot, ".turri", "jobs")),
@@ -1,4 +1,5 @@
1
1
  import { checkPlainTargets, formatCheckResults } from "./plain/check.js";
2
+ import { c } from "./module-report.js";
2
3
  const USAGE = `usage: turri validate <file.plain | directory> [options]
3
4
 
4
5
  Validates a ***plain specification statically: parses it, resolves its imports and
@@ -8,12 +9,6 @@ required modules, and reports every error without rendering anything.
8
9
  --json machine-readable output
9
10
 
10
11
  PLAIN_TEMPLATE_DIRS colon-separated template directories`;
11
- const c = {
12
- dim: (s) => `\x1b[2m${s}\x1b[0m`,
13
- bold: (s) => `\x1b[1m${s}\x1b[0m`,
14
- green: (s) => `\x1b[32m${s}\x1b[0m`,
15
- red: (s) => `\x1b[31m${s}\x1b[0m`,
16
- };
17
12
  const argv = process.argv.slice(2);
18
13
  const templateDirs = [];
19
14
  const positional = [];
@@ -43,10 +38,10 @@ if (json) {
43
38
  else {
44
39
  const output = formatCheckResults(results)
45
40
  .split("\n")
46
- .map((line) => line.startsWith("PASS") ? c.green(line) : line.startsWith("FAIL") ? c.red(line) : c.dim(line))
41
+ .map((line) => line.startsWith("PASS") ? c.success(line) : line.startsWith("FAIL") ? c.error(line) : c.dim(line))
47
42
  .join("\n");
48
43
  console.log(output);
49
44
  const failed = results.filter((r) => !r.ok).length;
50
- console.log(`\n${failed === 0 ? c.green(c.bold("all specs valid")) : c.red(c.bold(`${failed} of ${results.length} failed`))}`);
45
+ console.log(`\n${failed === 0 ? c.success(c.bold("all specs valid")) : c.error(c.bold(`${failed} of ${results.length} failed`))}`);
51
46
  }
52
47
  process.exit(results.every((r) => r.ok) ? 0 : 1);
package/docs/README.md CHANGED
@@ -1,20 +1,13 @@
1
1
  # turri documentation
2
2
 
3
- turri implements regenerative software: the \*\*\*plain specs are the durable definition of
4
- what a system does, and the code is generated from them, validated against them, and regenerated
5
- as they change. The [project README](../README.md) says why, and how to install and start; these
6
- pages go into each part.
3
+ turri implements regenerative software: the \*\*\*plain specs are the durable definition of what a system does, and the code is generated from them, validated against them, and regenerated as they change. The [project README](../README.md) says why, and how to install and start; these pages go into each part.
7
4
 
8
5
  ## Start here
9
6
 
10
- 1. [Installation](installation.md) - get a machine ready: `turri doctor`, and what turri needs of
11
- this machine.
12
- 2. [Using turri](using.md) - the conversation, the skills and tools, background jobs and
13
- their logs, choosing the model that renders, the command line.
14
- 3. [Authoring \*\*\*plain](authoring-plain.md) - writing the specs: what a spec is made of, the
15
- authoring rules, the skills that write and fix specs.
16
- 4. [Rendering](regenerating.md) - turning the specs into code: what each build does, in which order,
17
- and what has to pass before it moves on.
7
+ 1. [Installation](installation.md) - get a machine ready: `turri doctor`, and what turri needs of this machine.
8
+ 2. [Using turri](using.md) - the conversation, the skills and tools, background jobs and their logs, choosing the model that renders, the command line.
9
+ 3. [Authoring \*\*\*plain](authoring-plain.md) - writing the specs: what a spec is made of, the authoring rules, the skills that write and fix specs.
10
+ 4. [Rendering](regenerating.md) - turning the specs into code: what each build does, in which order, and what has to pass before it moves on.
18
11
 
19
12
  ## By question
20
13
 
@@ -1,14 +1,8 @@
1
1
  # Authoring \*\*\*plain
2
2
 
3
- Rendering turns a spec into code; authoring is the half that decides what gets built. The code is
4
- only ever as good as the spec - a fact in the wrong section is silently ignored, a functional spec
5
- that is too big comes out half-built, two specs that contradict each other break each other's
6
- tests. So this repo carries as much for writing specs as for rendering them: the authoring rules,
7
- a library of skills that apply them, and independent review of what they write.
3
+ Rendering turns a spec into code; authoring is the half that decides what gets built. The code is only ever as good as the spec - a fact in the wrong section is silently ignored, a functional spec that is too big comes out half-built, two specs that contradict each other break each other's tests. So this repo carries as much for writing specs as for rendering them: the authoring rules, a library of skills that apply them, and independent review of what they write.
8
4
 
9
- The rule underneath all of it: **the specs are the source of truth**. The generated code in
10
- `plain_modules/` is never edited by hand. A bug is fixed in the spec, and a change that is wanted
11
- goes into the spec - that is what persists and what the next render builds from.
5
+ The rule underneath all of it: **the specs are the source of truth**. The generated code in `plain_modules/` is never edited by hand. A bug is fixed in the spec, and a change that is wanted goes into the spec - that is what persists and what the next render builds from.
12
6
 
13
7
  ## A \*\*\*plain project
14
8
 
@@ -33,8 +27,7 @@ A `.plain` file is one module: optional YAML frontmatter, then up to four sectio
33
27
  | `***test reqs***` | everything about the black-box conformance tests: framework, how they run, mocking | `- :ConformanceTests: use pytest and call the CLI as a subprocess.` |
34
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:.` |
35
29
 
36
- Under a functional spec, a nested `***acceptance tests***` list states how that one
37
- functionality is checked end to end.
30
+ Under a functional spec, a nested `***acceptance tests***` list states how that one functionality is checked end to end.
38
31
 
39
32
  The frontmatter connects modules:
40
33
 
@@ -46,20 +39,13 @@ The frontmatter connects modules:
46
39
  | `exported_concepts` | which concepts a module that `requires` this one may use |
47
40
  | `required_concepts` | concepts an import module expects the importing module to define |
48
41
 
49
- Beyond that: a spec links to files under `resources/` with markdown link syntax, and the file's
50
- contents go to the renderer with the spec; lines starting with `>` are comments for people; and
51
- files are processed with Liquid first, so a template can be included with parameters.
42
+ Beyond that: a spec links to files under `resources/` with markdown link syntax, and the file's contents go to the renderer with the spec; lines starting with `>` are comments for people; and files are processed with Liquid first, so a template can be included with parameters.
52
43
 
53
- **Section ownership is the rule that bites.** The renderer reads each kind of fact only from the
54
- section that owns it. A tech choice written into a functional spec, or a behaviour written into
55
- the implementation reqs, is not flagged - it is simply not read.
44
+ **Section ownership is the rule that bites.** The renderer 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.
56
45
 
57
46
  ## The standard library
58
47
 
59
- turri ships a standard library of import modules in `stdlib/` that settle everything about a
60
- generic piece of software on one stack except what it does: its language and framework, layout,
61
- configuration, error handling, logging, shutdown, and how it is unit and conformance tested. A spec
62
- imports one and writes only its own concepts and functional specs:
48
+ 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 spec imports one and writes only its own concepts and functional specs:
63
49
 
64
50
  ```plain
65
51
  ---
@@ -82,13 +68,7 @@ import:
82
68
 
83
69
  It is built in three layers, and a stack imports the other two:
84
70
 
85
- - **The language** - `stdlib/lang/python`, `typescript`, `java`, `go`, `rust`: the version, the
86
- dependency manager, formatting, linting and type checking (ruff and mypy for Python; Prettier, ESLint
87
- and `tsc --noEmit` for TypeScript), how a failure is reported (an exception, a returned error, a
88
- `Result`), the logging library, and the unit test framework and layout. A module on a stack the library does not have can import its language alone.
89
- The formatter, linter and type checker a language names are enforced by the testing scripts, which
90
- run them with the tests - the unit testing script on the code, the conformance testing script on the
91
- tests - and count them as the tests (see [the static checks](regenerating.md#the-static-checks)).
71
+ - **The language** - `stdlib/lang/python`, `typescript`, `java`, `go`, `rust`: the version, the dependency manager, formatting, linting and type checking (ruff and mypy for Python; Prettier, ESLint and `tsc --noEmit` for TypeScript), how a failure is reported (an exception, a returned error, a `Result`), the logging library, and the unit test framework and layout. A module on a stack the library does not have can import its language alone. The formatter, linter and type checker a language names are enforced by the testing scripts, which run them with the tests - the unit testing script on the code, the conformance testing script on the tests - and count them as the tests (see [the static checks](regenerating.md#the-static-checks)).
92
72
  - **The kind's `common`** - what every stack of a kind shares:
93
73
 
94
74
  | kind | settles |
@@ -98,52 +78,23 @@ It is built in three layers, and a stack imports the other two:
98
78
  | cli | settings from flags, then `<TOOL>_<SETTING>`, then defaults; the work apart from parsing; errors as `Error: <message>` on standard error, exit 0, 1, 2 for a usage error, 130 on Ctrl-C, a stack trace only with `--debug`; logs on standard error, warnings by default, `--verbose`, `--debug` |
99
79
  | library | one public entry point; one base error type, with a dependency's errors wrapped; logs through the language's logging with no output set up; no environment variables, output or global state |
100
80
 
101
- - **The stack** - the framework and how it does each of those: for `python-flask`, an application
102
- factory, one Blueprint per resource, Pydantic for bodies, `@app.errorhandler` for the error body,
103
- structlog JSON logs with the request id bound in a hook, Gunicorn. For `go-cobra`, `RunE`
104
- commands with Cobra's own error printing off, so `main` alone writes the error and picks the exit
105
- code, and slog on standard error.
106
-
107
- Each conformance template imports its kind's `conformance/common`: a backend's tests start the
108
- built service on a free port and reach it over HTTP only, checking a failure by status and
109
- `error.code`; a frontend's run the served build in Chromium through Playwright with the backend
110
- stood in; a command-line tool's run the built tool as a process; a library's go through its public
111
- entry point.
112
-
113
- - **Conformance tests apart.** A spec without the conformance template has no test reqs, so no
114
- conformance tests are written or run for it. Turning them on later is adding that one import.
115
- - **A reserved name.** An import that starts with `stdlib/` is always turri's template, never
116
- a file of the project's. A project with a module at such a path - `stdlib/backend/python-fastapi.plain`
117
- beside the spec, in its `template/` folder or in `PLAIN_TEMPLATE_DIRS` - gets an error saying the
118
- name is reserved, so which one a spec builds on never depends on what is on disk beside it.
119
- - **No concepts.** Its requirements are on the predefined `:Implementation:`, `:UnitTests:` and
120
- `:ConformanceTests:` only, so it never collides with a spec's own definitions.
121
- - **Pinned to a toolchain.** It names its stack's toolchain - Python 3.12, Node.js 24, Java 21, Go 1.25, Rust -
122
- which the agents use from this machine; `turri doctor` says when the machine lacks it.
123
- - **Not storage, not the testing scripts.** A module with a database says which on top of its
124
- stack. It still needs its unit testing script, and a conformance testing script when it has
125
- conformance tests.
126
- - **Known to the agents.** The `stdlib` rule, in every spec-writing agent's system prompt, says when
127
- to import which, and lists every template with what it is and the folder it is in, read from
128
- `stdlib/` when the rules load. `spawn` and `brood` import a stack when the one chosen
129
- is in it, and its conformance template when conformance tests are on.
130
- - **Only what this machine can build.** The agents use this machine's toolchains and install none, so
131
- a Go stack on a laptop without Go stops at its first build. Every spec-writing agent and the
132
- conversation are told which of the standard library's languages the machine can build now - Python
133
- needs `uv`, TypeScript and every frontend `node` and `npm`, Go `go`, Rust `cargo`, Java a JDK
134
- (`src/stack.ts`, `toolchainsBlock`) - and `spawn` and `brood` offer, and choose, only stacks in those.
135
- A stack the person names in a language the machine lacks is not refused: they are told what to install
136
- first, and that `turri doctor` checks it.
137
-
138
- A requirement beyond the stack - storage, an outside service - is added on top of it. A module that
139
- differs from its stack on something the stack settles - another framework, another layout - writes
140
- its own instead: an import cannot be taken back in part.
81
+ - **The stack** - the framework and how it does each of those: for `python-flask`, an application factory, one Blueprint per resource, Pydantic for bodies, `@app.errorhandler` for the error body, structlog JSON logs with the request id bound in a hook, Gunicorn. For `go-cobra`, `RunE` commands with Cobra's own error printing off, so `main` alone writes the error and picks the exit code, and slog on standard error.
82
+
83
+ 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
+
85
+ - **Conformance tests apart.** A spec 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.
86
+ - **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 spec, in its `template/` folder or in `PLAIN_TEMPLATE_DIRS` - gets an error saying the name is reserved, so which one a spec builds on never depends on what is on disk beside it.
87
+ - **No concepts.** Its requirements are on the predefined `:Implementation:`, `:UnitTests:` and `:ConformanceTests:` only, so it never collides with a spec's own definitions.
88
+ - **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 every spec-writing agent's system prompt, 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. `spawn` and `brood` import a stack when the one chosen is in it, and its conformance template when conformance tests are on.
91
+ - **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 spec-writing agent 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 `spawn` and `brood` offer, and choose, 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
+
93
+ 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.
141
94
 
142
95
  ## The rules
143
96
 
144
- `genome/rules/` holds the authoring rules. They are in the system prompt of every agent that
145
- writes specs - the conversation, the interview skills, the reviewers - so they are not something
146
- an agent has to decide to go and read.
97
+ `genome/rules/` holds the authoring rules. They are in the system prompt of every agent that writes specs - the conversation, the interview skills, the reviewers - so they are not something an agent has to decide to go and read.
147
98
 
148
99
  | rule | covers |
149
100
  | --- | --- |
@@ -158,66 +109,39 @@ an agent has to decide to go and read.
158
109
  | `import-modules.md`, `requires-modules.md` | the two ways modules build on each other |
159
110
  | `exported-concepts.md`, `required-concepts.md` | which concepts cross module boundaries |
160
111
  | `integrations.md` (+ standalone, embedded, embedded testing) | specs for REST API integrations, deployed standalone or embedded in an existing codebase |
112
+ | `turri-regeneration.md` | turri's model of itself: a spec change regenerated as a spec diff, wherever it sits, in the chain's tip; what each kind of change sets off; what a coding agent sees; how bad code is fixed; where the cost is - so a spec is placed by what it means, never to spare regeneration |
161
113
  | `stdlib.md` | the standard library: when to import which template, and every template with what it is and where it is, read from `stdlib/` |
162
114
 
163
115
  The ones that shape a spec most:
164
116
 
165
- - **One functionality is at most ~200 lines of code.** A bigger one is split before it is written
166
- (`analyze-if-func-spec-too-complex`, `break-down-func-spec`).
167
- - **Functional specs are in build order.** Each is rendered on top of the ones before it.
168
- - **They state facts, with a concrete subject.** "A :User: can add a :Task:" - not "Implement
169
- adding tasks", not "The system should…".
170
- - **Nothing a test cannot check.** No `robust`, `seamless`, `as appropriate`; state the checkable
171
- fact or cut the word.
172
- - **No two specs contradict each other.** A conflict is found and resolved when a spec is added,
173
- not when its tests fail.
117
+ - **One functionality is at most ~200 lines of code.** A bigger one is split before it is written (`analyze-if-func-spec-too-complex`, `break-down-func-spec`).
118
+ - **Functional specs are in build order.** Each is rendered on top of the ones before it - which is what a spec may assume, not what a change costs: a spec inserted anywhere is regenerated alone.
119
+ - **They state facts, with a concrete subject.** "A :User: can add a :Task:" - not "Implement adding tasks", not "The system should…".
120
+ - **Nothing a test cannot check.** No `robust`, `seamless`, `as appropriate`; state the checkable fact or cut the word.
121
+ - **No two specs contradict each other.** A conflict is found and resolved when a spec is added, not when its tests fail.
174
122
 
175
123
  ## Writing specs with turri
176
124
 
177
- In a conversation (`turri`), say what you want and the matching skill runs. Two build a
178
- project from scratch, and write each spec change as a git diff that is built in the background the
179
- moment it is written. `brood` interviews you one question at a time and writes the specs as
180
- you answer; `spawn`, its quick twin, asks only what you want to build and which stack - or leaves the stack
181
- to it - and writes the rest on its own:
125
+ In a conversation (`turri`), say what you want and the matching skill runs. Two build a project from scratch, and write each spec change as a git diff that is built in the background the moment it is written. `brood` interviews you one question at a time and writes the specs as you answer; `spawn`, its quick twin, asks only what you want to build and which stack - or leaves the stack to it - and writes the rest on its own:
182
126
 
183
127
  | skill | phases | how a spec change is written |
184
128
  | --- | --- | --- |
185
129
  | `brood` | intent → stack → testing → product, feature by feature | first, how many questions the stack and product phases may ask - light 3, medium 5, thorough 10 or best judgement, broader with fewer, covering the same ground - and what they leave open turri decides itself, each decision a spec change of its own; every product answer is still a spec change, built before the next question; in testing, whether there are conformance tests, their `***test reqs***` and script - written as files, building nothing; then one spec change per answer, across whatever sections it needs, as a git diff with `write_spec_diff`, rendered as a render spec diff job and conformance tested as it is built |
186
130
  | `spawn` | intent → groundwork → product | only the intent and the stack are asked - the stack one question, `You choose` first, skipped when the user named one; the stack and the unit tests are written as files, with conformance tests off unless the user asks for them; then one spec change per feature, in build order, as a git diff with `write_spec_diff`, one after another with no answer between them. Changes after it are asked for in the conversation, as spec diffs, and what is left to build is worked out again from the spec |
187
131
 
188
- `mature` starts from a spec you already have, rough or hand-written, and runs on its own until
189
- it is fully rendered - every functionality built from the spec as it stands, its tests passing. It
190
- renders what is not built and watches the agents building it; when one struggles on something the
191
- spec leaves open or unclear - sent back again and again, the judge going back and forth, a spec
192
- conflict - it writes what the spec should say as a spec diff, stops that build, and renders it again.
193
- What the builds had to decide themselves - their assumptions, pitfalls, a failed build's diagnosis -
194
- goes into the spec the same way, when a user, a caller or a test can see it. It never asks: it takes
195
- the reading that fits the rest of the spec, and marks each such decision in its report. It leaves
196
- code, environment and turri problems to the builds, and stops when a functionality keeps
197
- struggling after the spec was clarified, when two cycles change nothing, or after twenty.
198
-
199
- For an existing project, `bud` works the same way, scoped to one feature: intent → scope → product.
200
- It first asks how many questions the product phase may ask - light, medium, thorough or best
201
- judgement, as `brood` does - then a short feature-intent interview, then product questions - a
202
- trigger and its outcome, an edge case, a rule - and every answer is a spec change, a git diff
203
- written with `write_spec_diff` and built the moment it is written, before the next question. What
204
- the questions leave open it decides itself, a spec change each. A change to something already
205
- specified, built or still to build, is put to the user first and is a spec diff too: what is left to
206
- build is worked out again from the spec. It ends on the person's confirmation of a short summary of
207
- the feature's changes.
132
+ `mature` starts from a spec you already have, rough or hand-written, and runs on its own until it is fully rendered - every functionality built from the spec as it stands, its tests passing. It renders what is not built and watches the agents building it; when one struggles on something the spec leaves open or unclear - sent back again and again, the judge going back and forth, a spec conflict - it writes what the spec should say as a spec diff, stops that build, and renders it again. What the builds had to decide themselves - their assumptions, pitfalls, a failed build's diagnosis - goes into the spec the same way, when a user, a caller or a test can see it. It never asks: it takes the reading that fits the rest of the spec, and marks each such decision in its report. It leaves code, environment and turri problems to the builds, and stops when a functionality keeps struggling after the spec was clarified, when two cycles change nothing, or after twenty.
133
+
134
+ For an existing project, `bud` works the same way, scoped to one feature: intent → scope → product. It first asks how many questions the product phase may ask - light, medium, thorough or best judgement, as `brood` does - then a short feature-intent interview, then product questions - a trigger and its outcome, an edge case, a rule - and every answer is a spec change, a git diff written with `write_spec_diff` and built the moment it is written, before the next question. What the questions leave open it decides itself, a spec change each. A change to something already specified, built or still to build, is put to the user first and is a spec diff too: what is left to build is worked out again from the spec. It ends on the person's confirmation of a short summary of the feature's changes.
208
135
 
209
136
  What keeps the interview honest is the harness, not the interviewer:
210
137
 
211
- - **Every question offers choices** (`ask_user` refuses a question without them), and each
212
- answer maps to one spec change.
213
- - **Every answer is written before the next question.** In the product phase of `brood` and `bud`, `ask_user` refuses
214
- a new question until the last answer is a spec change - see [skills and gates](skills-and-gates.md).
138
+ - **Every question offers choices** (`ask_user` refuses a question without them), and each answer maps to one spec change.
139
+ - **Every answer is written before the next question.** In the product phase of `brood` and `bud`, `ask_user` refuses a new question until the last answer is a spec change - see [skills and gates](skills-and-gates.md).
215
140
  - **Each phase ends on the person's confirmation** of a short summary, not on the interviewer's word.
216
141
 
217
142
  ## The skills
218
143
 
219
- Every skill in `genome/skills/` can be run from a conversation; most are also used by the bigger ones. A project's own,
220
- in `.turri/skills/` or `.agents/skills/`, can be too (see [skills and gates](skills-and-gates.md#a-projects-own-skills)).
144
+ Every skill in `genome/skills/` can be run from a conversation; most are also used by the bigger ones. A project's own, in `.turri/skills/` or `.agents/skills/`, can be too (see [skills and gates](skills-and-gates.md#a-projects-own-skills)).
221
145
 
222
146
  | to… | skills |
223
147
  | --- | --- |
@@ -229,8 +153,7 @@ in `.turri/skills/` or `.agents/skills/`, can be too (see [skills and gates](ski
229
153
  | restructure modules | `create-import-module`, `create-requires-module`, `refactor-module`, `consolidate-concepts` |
230
154
  | set up the project to build | `implement-unit-testing-script`, `implement-conformance-testing-script`, `check-plain-env` |
231
155
 
232
- `debug-specs` is the one for a running application that misbehaves: it reads the generated code
233
- to find the cause, traces it back to the spec, and fixes only the `.plain` files.
156
+ `debug-specs` is the one for a running application that misbehaves: it reads the generated code to find the cause, traces it back to the spec, and fixes only the `.plain` files.
234
157
 
235
158
  ## Checking a spec
236
159
 
@@ -238,11 +161,6 @@ to find the cause, traces it back to the spec, and fixes only the `.plain` files
238
161
  turri validate app.plain # or validate in a conversation
239
162
  ```
240
163
 
241
- It parses the spec with this repo's own parser, resolves its imports and required modules, and
242
- reports every syntax, concept and structure error with its line - no model, no API key. The
243
- interview skills run it before a phase ends, and `write_spec_diff`
244
- refuses a change that leaves a file that does not parse. Pass the project directory to check every
245
- module at once.
164
+ It parses the spec 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 `write_spec_diff` refuses a change that leaves a file that does not parse. Pass the project directory to check every module at once.
246
165
 
247
- What `check` cannot see - a fact in the wrong section, a spec that is too big, two that conflict,
248
- wording no test can check - is what the rules, the skills and the reviewers are for.
166
+ What `check` cannot see - a fact in the wrong section, a spec that is too big, two that conflict, wording no test can check - is what the rules, the skills and the reviewers are for.