@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.
- package/.pi/themes/turri-dark.json +67 -66
- package/.pi/themes/turri-light.json +71 -73
- package/README.md +40 -128
- package/assets/jellyfish/dark-00.png +0 -0
- package/assets/jellyfish/dark-01.png +0 -0
- package/assets/jellyfish/dark-02.png +0 -0
- package/assets/jellyfish/dark-03.png +0 -0
- package/assets/jellyfish/dark-04.png +0 -0
- package/assets/jellyfish/dark-05.png +0 -0
- package/assets/jellyfish/dark-06.png +0 -0
- package/assets/jellyfish/dark-07.png +0 -0
- package/assets/jellyfish/dark-08.png +0 -0
- package/assets/jellyfish/dark-09.png +0 -0
- package/assets/jellyfish/dark-10.png +0 -0
- package/assets/jellyfish/dark-11.png +0 -0
- package/assets/jellyfish/light-00.png +0 -0
- package/assets/jellyfish/light-01.png +0 -0
- package/assets/jellyfish/light-02.png +0 -0
- package/assets/jellyfish/light-03.png +0 -0
- package/assets/jellyfish/light-04.png +0 -0
- package/assets/jellyfish/light-05.png +0 -0
- package/assets/jellyfish/light-06.png +0 -0
- package/assets/jellyfish/light-07.png +0 -0
- package/assets/jellyfish/light-08.png +0 -0
- package/assets/jellyfish/light-09.png +0 -0
- package/assets/jellyfish/light-10.png +0 -0
- package/assets/jellyfish/light-11.png +0 -0
- package/dist/ask.js +34 -15
- package/dist/brand.js +7 -7
- package/dist/cli-options.js +12 -6
- package/dist/config-edit.js +1 -0
- package/dist/config.js +5 -2
- package/dist/cultivate-cli.js +16 -23
- package/dist/extension.js +59 -67
- package/dist/init-config.js +5 -0
- package/dist/jellyfish.js +130 -0
- package/dist/loop-cli.js +19 -7
- package/dist/loop-tools.js +11 -5
- package/dist/module-report.js +5 -4
- package/dist/pi.js +76 -19
- package/dist/question-dialog.js +1 -0
- package/dist/regenerate/activity.js +21 -0
- package/dist/regenerate/list-arguments.js +121 -0
- package/dist/regenerate/loop.js +21 -8
- package/dist/regenerate/plain-palette.js +52 -37
- package/dist/regenerate/regenerate.js +4 -2
- package/dist/regenerate/self-check.js +13 -6
- package/dist/regenerate/side-panel.js +1 -1
- package/dist/regenerate/spec-map-view.js +9 -5
- package/dist/regenerate/test-scripts.js +54 -10
- package/dist/regenerate/unit-review.js +1 -1
- package/dist/regenerate-cli.js +11 -5
- package/dist/release-cli.js +3 -8
- package/dist/review/live.js +2 -1
- package/dist/run-report.js +39 -1
- package/dist/validate-cli.js +3 -8
- package/docs/README.md +5 -12
- package/docs/authoring-plain.md +37 -119
- package/docs/config.md +53 -178
- package/docs/deploy.md +21 -80
- package/docs/development.md +13 -41
- package/docs/headless.md +45 -121
- package/docs/images/how-turri-works.svg +29 -31
- package/docs/images/turri-banner.png +0 -0
- package/docs/installation.md +13 -40
- package/docs/parser.md +15 -43
- package/docs/regenerating.md +229 -938
- package/docs/sandbox.md +38 -152
- package/docs/skills-and-gates.md +50 -171
- package/docs/theming.md +45 -46
- package/docs/using.md +69 -345
- package/genome/rules/bullet-continuation.md +5 -13
- package/genome/rules/concise-specs-examples.md +2 -4
- package/genome/rules/concise-specs-integration-examples.md +2 -6
- package/genome/rules/concise-specs.md +1 -2
- package/genome/rules/func-specs.md +1 -0
- package/genome/rules/integration-embedded-testing.md +1 -4
- package/genome/rules/integrations.md +1 -2
- package/genome/rules/project-model.md +14 -35
- package/genome/rules/stdlib.md +14 -49
- package/genome/rules/turri-regeneration.md +48 -0
- package/genome/skills/add-implementation-requirement/SKILL.md +1 -2
- package/genome/skills/analyze-if-func-spec-too-complex/SKILL.md +3 -8
- package/genome/skills/brood/SKILL.md +37 -127
- package/genome/skills/brood/references/intent.md +4 -12
- package/genome/skills/brood/references/product.md +24 -76
- package/genome/skills/brood/references/stack.md +7 -29
- package/genome/skills/brood/references/testing.md +11 -42
- package/genome/skills/bud/SKILL.md +32 -109
- package/genome/skills/bud/references/intent.md +4 -11
- package/genome/skills/implement-conformance-testing-script/SKILL.md +3 -6
- package/genome/skills/implement-unit-testing-script/SKILL.md +1 -2
- package/genome/skills/mature/SKILL.md +21 -69
- package/genome/skills/refactor-module/SKILL.md +24 -2
- package/genome/skills/spawn/SKILL.md +28 -113
- package/package.json +1 -1
- package/assets/jellyfish/dark-12.png +0 -0
- package/assets/jellyfish/dark-13.png +0 -0
- package/assets/jellyfish/dark-14.png +0 -0
- package/assets/jellyfish/fallback.txt +0 -252
- package/assets/jellyfish/light-12.png +0 -0
- package/assets/jellyfish/light-13.png +0 -0
- package/assets/jellyfish/light-14.png +0 -0
package/docs/using.md
CHANGED
|
@@ -7,19 +7,7 @@ cd ~/my-project
|
|
|
7
7
|
turri
|
|
8
8
|
```
|
|
9
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
|
-
turri's version (and, run from a clone, the commit it is on, and whether the clone has changes), where commands
|
|
17
|
-
will run, the rules and skills loaded - rather than pi's startup header and resource list; `turri --verbose` shows
|
|
18
|
-
those too. pi's "Update Available" notice is left out - turri's pi is a pinned dependency `pi update` never
|
|
19
|
-
touches - and the terminal's tab reads `🪼 turri - <folder>`, not pi's `π`. Talk to it: ask it to start a
|
|
20
|
-
project, add a feature, render a module, fix a spec. It decides which skill or tool applies - but
|
|
21
|
-
not *how* a skill runs: `cultivate` hands the work to the gated runner, which owns the steps, the
|
|
22
|
-
gates and the judges (see [skills and gates](skills-and-gates.md)).
|
|
10
|
+
That is pi, with turri's tools, skills and themes loaded - `turri` alone, or with pi's options (`turri -c`, `turri --harness-model <m>`). It opens with turri's own banner - the jellyfish it is named after, swimming until the conversation fills the screen: a pixel jellyfish - a pink bell, an orange gut, neon tentacles coming apart into code at their tips - swimming a stroke a loop, its bell shutting and rising, its tentacles following: a picture in a terminal that shows images (Kitty, Ghostty, WezTerm, Warp, iTerm2), and drawn smaller in half blocks in any other, tmux included (`src/jellyfish.ts` draws it, `scripts/jellyfish-frames.mjs` writes the pictures) - turri's version (and, run from a clone, the commit it is on, and whether the clone has changes) and where its settings are changed - and only when something is wrong, skills that failed to load or agents' commands less fenced than they should be - rather than pi's startup header and resource list; `turri --verbose` shows those too. pi's "Update Available" notice is left out - turri's pi is a pinned dependency `pi update` never touches - and the terminal's tab reads `🪼 turri - <folder>`, not pi's `π`. Talk to it: ask it to start a project, add a feature, render a module, fix a spec. It decides which skill or tool applies - but not *how* a skill runs: `cultivate` hands the work to the gated runner, which owns the steps, the gates and the judges (see [skills and gates](skills-and-gates.md)).
|
|
23
11
|
|
|
24
12
|
The skills that build from scratch:
|
|
25
13
|
|
|
@@ -29,28 +17,17 @@ The skills that build from scratch:
|
|
|
29
17
|
| `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 |
|
|
30
18
|
| `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 |
|
|
31
19
|
|
|
32
|
-
Peeking is safe while a question is open - a skill's or the chat's: `ctrl+h` opens the side panel over the question,
|
|
33
|
-
which waits under it as it was - the panel says `your question is waiting`, and `ctrl+h` or `esc` takes you back to
|
|
34
|
-
answer it. (The question has the keys, so turri catches `ctrl+h` itself while one is open.) The dialog holds the question
|
|
35
|
-
alone - no hint and no invitation; the `ctrl+h` under the job panel breathes until it is first pressed.
|
|
20
|
+
Peeking is safe while a question is open - a skill's or the chat's: `ctrl+h` opens the side panel over the question, which waits under it as it was - the panel says `your question is waiting`, and `ctrl+h` or `esc` takes you back to answer it. (The question has the keys, so turri catches `ctrl+h` itself while one is open.) The dialog holds the question alone - no hint and no invitation; the `ctrl+h` under the job panel breathes until it is first pressed.
|
|
36
21
|
|
|
37
|
-
While a skill runs, a line above the input shows its phases, every one by name - those done ticked, the one it is in
|
|
38
|
-
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
|
|
39
|
-
phases centred between them, `✓ intent ━━━━ ⠋ stack ──── ○ testing ──── ○ product`. Under it, dimmed, the phase it is in and what
|
|
40
|
-
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,
|
|
41
|
-
`⠹ add-test-requirement`.
|
|
22
|
+
While a skill runs, a line above the input shows its phases, every one by name - those done ticked, the one it is in 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 phases centred between them, `✓ intent ━━━━ ⠋ stack ──── ○ testing ──── ○ product`. Under it, dimmed, the phase it is in and what 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, `⠹ add-test-requirement`.
|
|
42
23
|
|
|
43
|
-
`genome/skills/` holds the rest: adding a feature, a concept, a requirement, a resource; splitting a spec
|
|
44
|
-
that is too big; resolving conflicts; checking the environment - see
|
|
45
|
-
[authoring \*\*\*plain](authoring-plain.md#the-skills). A skill run that is interrupted can be resumed
|
|
46
|
-
where it stopped. A project can have skills of its own, in `.turri/skills/` or `.agents/skills/` - see
|
|
47
|
-
[skills and gates](skills-and-gates.md#a-projects-own-skills).
|
|
24
|
+
`genome/skills/` holds the rest: adding a feature, a concept, a requirement, a resource; splitting a spec that is too big; resolving conflicts; checking the environment - see [authoring \*\*\*plain](authoring-plain.md#the-skills). A skill run that is interrupted can be resumed where it stopped. A project can have skills of its own, in `.turri/skills/` or `.agents/skills/` - see [skills and gates](skills-and-gates.md#a-projects-own-skills).
|
|
48
25
|
|
|
49
26
|
## The tools
|
|
50
27
|
|
|
51
28
|
| tool | |
|
|
52
29
|
| --- | --- |
|
|
53
|
-
| `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 |
|
|
30
|
+
| `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 - `"chain"` for every module of its requires chain too, built again from the bottom - only when you ask, or agree |
|
|
54
31
|
| `drift` | what is left to regenerate: how far the code and its conformance tests have drifted from the spec, starting nothing |
|
|
55
32
|
| `glimpse` | the pulse a module's codebases would start next, and the whole prompt its coding agent would get - starting nothing |
|
|
56
33
|
| `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 |
|
|
@@ -63,90 +40,27 @@ where it stopped. A project can have skills of its own, in `.turri/skills/` or `
|
|
|
63
40
|
| `lineage` | a module's lineage: what each regeneration and conformance run changed in it, and what it was regenerated from |
|
|
64
41
|
| `cultivate` | run a gated skill, its steps and review gates enforced |
|
|
65
42
|
| `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) |
|
|
66
|
-
| `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 |
|
|
43
|
+
| `ask_user` | put a question to you as a dialog to pick from - several at once, each a box you tick and untick, "Something else…" to type, or "Chat about this" to talk it over first; Esc in either goes back to the options |
|
|
67
44
|
| `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` |
|
|
68
45
|
|
|
69
46
|
What each render does, in order, is in [regenerating the code](regenerating.md).
|
|
70
47
|
|
|
71
|
-
The conversation knows the ***plain standard library from its first turn: the stdlib rule in its
|
|
72
|
-
system prompt lists every stack and where the templates are, so "build this as a Flask backend"
|
|
73
|
-
becomes an import of `stdlib/backend/python-flask`, not a stack written out by hand. The banner at
|
|
74
|
-
start says how many stacks there are, and **`/stdlib`** lists them, each with what it is (see
|
|
75
|
-
[the standard library](authoring-plain.md#the-standard-library)).
|
|
48
|
+
The conversation knows the ***plain standard library from its first turn: the stdlib rule in its system prompt lists every stack and where the templates are, so "build this as a Flask backend" becomes an import of `stdlib/backend/python-flask`, not a stack written out by hand. The banner at start says how many stacks there are, and **`/stdlib`** lists them, each with what it is (see [the standard library](authoring-plain.md#the-standard-library)).
|
|
76
49
|
|
|
77
|
-
The agent does this work with these tools, never by running turri's command line - or
|
|
78
|
-
another pi - through its shell: that would be a separate, headless run outside regen
|
|
79
|
-
and `/halt`. The harness refuses such a command unless your message asks for the
|
|
80
|
-
command line ("run it headless", "use the CLI", or the command itself). pi configuring itself -
|
|
81
|
-
`pi install`, `update`, `list`, `config`, `auth`, its settings - is not affected.
|
|
50
|
+
The agent does this work with these tools, never by running turri's command line - or another pi - through its shell: that would be a separate, headless run outside regen and `/halt`. The harness refuses such a command unless your message asks for the command line ("run it headless", "use the CLI", or the command itself). pi configuring itself - `pi install`, `update`, `list`, `config`, `auth`, its settings - is not affected.
|
|
82
51
|
|
|
83
52
|
## Pulses
|
|
84
53
|
|
|
85
|
-
A pulse is one unit of work regenerating the code. It was called a job, and still is where a name is kept -
|
|
86
|
-
|
|
87
|
-
the
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
one
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
modules or ten. How many run at once is capped by what the machine has room for: past
|
|
96
|
-
`parallel-jobs` (see [the project config](config.md#how-many-jobs-at-once)), a pulse whose turn has
|
|
97
|
-
come waits for a free slot, and says so.
|
|
98
|
-
|
|
99
|
-
- **The panel** above the input, while something runs, shows on top what finished - a line a module, its
|
|
100
|
-
pulses oldest first, each with its mark (green, red or amber, as in the side panel), number and kind - what
|
|
101
|
-
it regenerated is in the side panel - `cognio … 2 earlier · ✓ 3 regenerate · ✓ 4 conformance`, the newest that fit the width -
|
|
102
|
-
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,
|
|
103
|
-
before any pulse runs - `shorty · planning the pulses · 12s` - the planner is an agent, and takes a while; a
|
|
104
|
-
`/regenerate` says it began the moment it is sent. Pulses are numbered within their module, as regen numbers
|
|
105
|
-
them. `ctrl+o` expands the agents' trace alone; what finished stays a line a module. The line of keys under
|
|
106
|
-
it - `ctrl+o to expand the trace · ctrl+h to peek at regen` - has each key breathing, fully there to a little
|
|
107
|
-
faint and back, until it is first pressed: once `ctrl+o` has opened the trace, or the side panel has been opened,
|
|
108
|
-
that key is still for the rest of the session and the other breathes on.
|
|
109
|
-
What waits is not in it, and it shows no spec diff - the side panel has both. With nothing running it
|
|
110
|
-
is gone.
|
|
111
|
-
- **A pulse's change** is what its agent works from, not a text diff of the module's file: the items
|
|
112
|
-
`<spec change>` gives the agent - only what the pulse's functional specs use, an import's items as
|
|
113
|
-
well as the module's own, a code pulse's without the test reqs - each in the file it is written in,
|
|
114
|
-
under its section, in the file's order (`change-view.ts`).
|
|
115
|
-
- **A spec diff**, in the side panel, reads as an editor shows a diff: its \*\*\*plain highlighted
|
|
116
|
-
as [plyn](https://github.com/plainlang/plyn) highlights it - section headers, concepts, names in
|
|
117
|
-
backticks, text in quotes, links, the front matter - each added line filled green and each removed one
|
|
118
|
-
red, the text on top, the fill the width of the panel ([colours](theming.md#spec-diffs)). It is shown
|
|
119
|
-
file by file, each file's lines together under its name, with what it adds and takes out - the module
|
|
120
|
-
being rendered first, the rest by name, and none the diff does not change. Each line has its number in
|
|
121
|
-
that file: a spec diff is of the spec as read, with what it imports laid in, so a line is placed in the
|
|
122
|
-
file it is written in - its links read as the parser renders them - and a removed line, in no file now,
|
|
123
|
-
goes with the change it is part of and has no number. A line is never put in a file on a guess: one
|
|
124
|
-
that cannot be placed is listed last, under "not found in the spec's files". Where lines of a file are not in
|
|
125
|
-
the diff, `↕ 28 lines` says how many, as GitHub does - `↑` above the first - and names the section
|
|
126
|
-
the lines under it are in when it is another than the one above, `↕ 28 lines · ***functional specs***`,
|
|
127
|
-
as GitHub names a hunk's function: each section is named once.
|
|
128
|
-
- **The side panel** (`ctrl+h`, as it was left - but on the pulse that last failed, stopped or did not pass, when one has
|
|
129
|
-
since it was last opened: the live panel that showed it is gone with the last pulse, and its announcement in the chat
|
|
130
|
-
says `ctrl+h shows this pulse`; **`/pulses`** on the pulses; not `ctrl+j`, which a terminal without the Kitty
|
|
131
|
-
keyboard protocol sends as a line feed, the same as `shift+enter`, and which a dialog takes for
|
|
132
|
-
`enter`; both stay pi's new-line keys. `ctrl+h` is the byte old terminals sent for backspace; a
|
|
133
|
-
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 -
|
|
134
|
-
or, `s`, sits beside the chat: the chat on the left, the panel in the right half of the screen, and `s` again
|
|
135
|
-
over the whole screen. It opens as it was last left, for the conversation; a terminal under 100 columns has
|
|
136
|
-
no room for both and shows the panel over the whole screen.
|
|
137
|
-
It opens on **regen**: the spec itself, in full, with how much of it the code has been regenerated from drawn
|
|
138
|
-
onto it.
|
|
139
|
-
|
|
140
|
-
Every item of the spec - a definition, a req, a functional spec with its sub-bullets and acceptance tests,
|
|
141
|
-
what turri plans and diffs by - is a row in the file's order, its \*\*\*plain highlighted as plyn highlights it
|
|
142
|
-
(as a spec diff is) and wrapped to the width, never cut short. The map has two columns, each headed on the
|
|
143
|
-
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
|
|
144
|
-
spec. The top of the panel is where it is seen first: the top line, the module tabs, and the keys - each view's,
|
|
145
|
-
`d talk it through in the chat` first when the module needs you - wrapped, never cut short, a line of space between
|
|
146
|
-
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
|
|
147
|
-
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
|
|
148
|
-
mark, up the ladder. It names every rung, whatever the page shows - to take out only where something is - and a
|
|
149
|
-
panel under 60 columns wide has none.
|
|
54
|
+
A pulse is one unit of work regenerating the code. It was called a job, and still is where a name is kept - `job_id`, `parallel-jobs`, `allow-to-stop-jobs`, `.turri/jobs/` - and in a project's own files written before: the chat is told the two are the same, so an `AGENTS.md` or a skill that says "job" needs no change.
|
|
55
|
+
|
|
56
|
+
A render takes minutes, so in the TUI every render tool starts the work as a pulse and returns straight away. The conversation carries on; pulses on the same module - or on modules of one `requires` chain - queue behind each other, in the order they were asked for, from the first pulse on: one queued while the spec is only a scaffold, with no functional specs yet, or while it does not parse, still holds its module, so nothing on the module runs beside it. Pulses on modules that share nothing run side by side, each with its own progress panel - two modules or ten. How many run at once is capped by what the machine has room for: past `parallel-jobs` (see [the project config](config.md#how-many-jobs-at-once)), a pulse whose turn has come waits for a free slot, and says so.
|
|
57
|
+
|
|
58
|
+
- **The panel** above the input, while something runs, shows on top what finished - a line a module, its pulses oldest first, each with its mark (green, red or amber, as in the side panel), number and kind - what it regenerated is in the side panel - `cognio … 2 earlier · ✓ 3 regenerate · ✓ 4 conformance`, the newest that fit the width - 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, before any pulse runs - `shorty · planning the pulses · 12s` - the planner is an agent, and takes a while; a `/regenerate` says it began the moment it is sent. Pulses are numbered within their module, as regen numbers them. `ctrl+o` expands the agents' trace alone; what finished stays a line a module. The line of keys under it - `ctrl+o to expand the trace · ctrl+h to peek at regen` - has each key breathing, fully there to a little faint and back, until it is first pressed: once `ctrl+o` has opened the trace, or the side panel has been opened, that key is still for the rest of the session and the other breathes on. What waits is not in it, and it shows no spec diff - the side panel has both. With nothing running it is gone.
|
|
59
|
+
- **A pulse's change** is what its agent works from, not a text diff of the module's file: the items `<spec change>` gives the agent - only what the pulse's functional specs use, an import's items as well as the module's own, a code pulse's without the test reqs - each in the file it is written in, under its section, in the file's order (`change-view.ts`).
|
|
60
|
+
- **A spec diff**, in the side panel, reads as an editor shows a diff: its \*\*\*plain highlighted as [plyn](https://github.com/plainlang/plyn) highlights it - section headers, concepts, names in backticks, text in quotes, links, the front matter - each added line filled green and each removed one red, the text on top, the fill the width of the panel ([colours](theming.md#spec-diffs)). It is shown file by file, each file's lines together under its name, with what it adds and takes out - the module being rendered first, the rest by name, and none the diff does not change. Each line has its number in that file: a spec diff is of the spec as read, with what it imports laid in, so a line is placed in the file it is written in - its links read as the parser renders them - and a removed line, in no file now, goes with the change it is part of and has no number. A line is never put in a file on a guess: one that cannot be placed is listed last, under "not found in the spec's files". Where lines of a file are not in the diff, `↕ 28 lines` says how many, as GitHub does - `↑` above the first - and names the section the lines under it are in when it is another than the one above, `↕ 28 lines · ***functional specs***`, as GitHub names a hunk's function: each section is named once.
|
|
61
|
+
- **The side panel** (`ctrl+h`, as it was left - but on the pulse that last failed, stopped or did not pass, when one has since it was last opened: the live panel that showed it is gone with the last pulse, and its announcement in the chat says `ctrl+h shows this pulse`; **`/pulses`** on the pulses; not `ctrl+j`, which a terminal without the Kitty keyboard protocol sends as a line feed, the same as `shift+enter`, and which a dialog takes for `enter`; both stay pi's new-line keys. `ctrl+h` is the byte old terminals sent for backspace; a 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 - or, `s`, sits beside the chat: the chat on the left, the panel in the right half of the screen, and `s` again over the whole screen. It opens as it was last left, for the conversation; a terminal under 100 columns has no room for both and shows the panel over the whole screen. It opens on **regen**: the spec itself, in full, with how much of it the code has been regenerated from drawn onto it.
|
|
62
|
+
|
|
63
|
+
Every item of the spec - a definition, a req, a functional spec with its sub-bullets and acceptance tests, what turri plans and diffs by - is a row in the file's order, its \*\*\*plain highlighted as plyn highlights it (as a spec diff is) and wrapped to the width, never cut short. The map has two columns, each headed on the 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 spec. The top of the panel is where it is seen first: the top line, the module tabs, and the keys - each view's, `d talk it through in the chat` first when the module needs you - wrapped, never cut short, a line of space between 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 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 mark, up the ladder. It names every rung, whatever the page shows - to take out only where something is - and a panel under 60 columns wide has none.
|
|
150
64
|
|
|
151
65
|
| Mark | Legend | Means |
|
|
152
66
|
| --- | --- | --- |
|
|
@@ -158,178 +72,43 @@ come waits for a free slot, and says so.
|
|
|
158
72
|
| `!` | needs you | in the pulse that did not land and halted the module, or the planner found no plan |
|
|
159
73
|
| `−` | 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 |
|
|
160
74
|
|
|
161
|
-
`◇` and `◆` are both green, and mean the same whatever `conformance-tests:` says: a functional spec regenerated
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
One module is shown at a time, with a tab for each module of the chain on the line under the top line, in
|
|
187
|
-
the chain's order - the module it is built on to the left: `d365_version_api [d365_http_client] d365_utils
|
|
188
|
-
12 ›`. A tab regenerating spins, one stuck says `!`; what does not fit is counted at either end. `←` `→` go from
|
|
189
|
-
one tab to the next. The module shown is the one in focus - the one regenerating now, else the one asked for,
|
|
190
|
-
else the first - until you pick another tab; it goes back to following once another module is in focus, or
|
|
191
|
-
the one in focus starts regenerating. Under the module's own text is what it imports, under **imported**, a
|
|
192
|
-
folded block a file, `▸ from stdlib/backend/python-fastapi · 7 reqs · all built`, closed until opened. The
|
|
193
|
-
modules it requires are tabs of their own: a chain of many modules is never drawn nested, one in the next.
|
|
194
|
-
A map longer than the screen has a minimap down its right edge, a cell a slice in the colour of
|
|
195
|
-
its most pressing mark, the slice shown solid. The map is read from the files - the code record, the
|
|
196
|
-
`.plain` files, the tests record - so it is right the moment turri opens a project, before anything runs;
|
|
197
|
-
the work loop's plan adds the pulses on top. It maps the files asked to build this conversation, else
|
|
198
|
-
`module:` in `config.turri.yaml`, else the `.plain` files of the folder that no other one there imports or
|
|
199
|
-
requires - the folder's files looked at again only once one of them, or its config, changes. `↑` `↓` move
|
|
200
|
-
row by row, `enter` or `space` open and close an item or an import block - a functional spec opens to its
|
|
201
|
-
sub-bullets and its `***acceptance tests***`, nested under it as the spec has them - `←` `→` go to the next module's
|
|
202
|
-
tab, `o` and `c` open or close everything shown, `pgup` `pgdn` and the
|
|
203
|
-
wheel scroll, `g`/`G` go to the top and the bottom.
|
|
204
|
-
|
|
205
|
-
`p` goes to the **pulses** - and back - onto the pulse that regenerates the item under the cursor, and
|
|
206
|
-
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
|
|
207
|
-
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
|
|
208
|
-
finished one's mark green when it passed, red when it failed or did not pass, amber when it was stopped.
|
|
209
|
-
Opened, a running one shows what it is doing; a queued one, what it waits for; a finished one, its agents
|
|
210
|
-
and what each spent, and whether it did not pass. Under it is a row
|
|
211
|
-
for each file its spec diff changes - the file of the module being rendered first and open, the rest by
|
|
212
|
-
name and closed - each opening onto that file's lines. A file with nothing added or taken out is not
|
|
213
|
-
listed. `↑` `↓` move, `enter` or `space` open and close what is under the cursor, `→` `←` open and close
|
|
214
|
-
(`←` on a closed pulse goes to its section, on a closed file to its pulse), `o` and `c` open or close every
|
|
215
|
-
pulse of the section - or, on a file, every file of its pulse - `pgup` `pgdn` and the wheel scroll, `g`/`G`
|
|
216
|
-
go to the top and the bottom. The cursor stays on its row when the pulse under it moves on; a pulse opened
|
|
217
|
-
closes when it moves to another section. What is open is kept while the panel is closed. What the agents
|
|
218
|
-
said and did is not shown - it is in each pulse's log (see [Agent logs](#agent-logs)).
|
|
219
|
-
|
|
220
|
-
`ctrl+h` again, or `esc`, closes it and goes back to the chat. Beside the chat, a click decides which side has
|
|
221
|
-
the keys - the chat or the panel, the one clicked, or the one `⌥⌘←` / `⌥⌘→` points at (on a
|
|
222
|
-
terminal that passes ⌘ on, over the Kitty keyboard protocol - Ghostty, kitty, WezTerm, iTerm2; not Apple's Terminal);
|
|
223
|
-
the other is drawn faint - and `esc` gives the chat the keys too, the panel staying and
|
|
224
|
-
following the pulses; `ctrl+h` gives the panel the keys again, and from the panel closes it. (pi's regular screen,
|
|
225
|
-
`--tui-mode regular`, reads no mouse: there it is the keys alone.)
|
|
226
|
-
While the panel has the keys, every key is the panel's,
|
|
227
|
-
whatever else happens: a question the chat model asks in the background (`ask_user`) waits in the chat,
|
|
228
|
-
unanswered - an `enter` in the panel never answers it - and the panel's top line says "the chat is waiting
|
|
229
|
-
for your answer". Back in the chat, the question is there, with the keys.
|
|
230
|
-
- `turri` runs pi in fullscreen mode, so the conversation stays where you scroll it while
|
|
231
|
-
the pulses redraw (PgUp/PgDn, the wheel); `--tui-mode regular` goes back to the terminal's own
|
|
232
|
-
scrollback.
|
|
233
|
-
- **`/turri-config`** changes a setting of the project's `config.turri.yaml` - the models, review, conformance tests, any
|
|
234
|
-
key - and says when it takes effect: now, at your next message, or at the next pulse; never only after a restart.
|
|
235
|
-
See [changing it from the chat](config.md#changing-it-from-the-chat).
|
|
236
|
-
- **`/stack`** chooses the stack everything is built with from then on, in a project whose parts are on different
|
|
237
|
-
stacks: a list of the project's stacks, or `/stack backend`, `/stack none`. The stack's `config.turri.<stack>.yaml`
|
|
238
|
-
is laid over `config.turri.yaml` - its testing scripts, toolchains, models - for the session; a pulse already
|
|
239
|
-
running keeps the stack it started with. The chat model switches it too when you ask. See
|
|
240
|
-
[stacks](config.md#stacks).
|
|
241
|
-
- **`/regenerate [module | file.plain] [functionality ...] [from scratch] [how to cut the work]`** regenerates a module from its spec as it is now, as
|
|
242
|
-
the `regenerate` tool does: what is left to regenerate is planned into pulses - one functional spec at a time, a few
|
|
243
|
-
together or the whole module in one, as the planner judges - and the first starts. Words after the module are
|
|
244
|
-
guidance for that plan (`/regenerate app models first`). A module's name typed with spaces for its underscores is
|
|
245
|
-
that module - `/regenerate d365_function executor` is `d365_function_executor`. With no module named: the one `module:` in
|
|
246
|
-
`config.turri.yaml` names, else the folder's top modules, to pick from. Asked for from scratch - `from scratch`,
|
|
247
|
-
`start over`, `delete the module` - it asks first, then deletes the module's code and conformance tests in every
|
|
248
|
-
codebase where they live, committed so `/lineage` keeps them, and regenerates the whole module from its spec,
|
|
249
|
-
built though nothing in it changed: `/regenerate shorty from scratch`. The chat's `regenerate` does the same with
|
|
250
|
-
`from_scratch`, when you ask for it; `turri regenerate --from-scratch` on the command line, not with `--dry-run`.
|
|
251
|
-
Functionalities named after the module - `/regenerate shorty 3 5` - are regenerated though their spec did not
|
|
252
|
-
change, on the model chosen for functionalities: as `turri regenerate shorty.plain 3 5` does, and the chat's
|
|
253
|
-
`regenerate` with `functionalities`.
|
|
254
|
-
- **`/halt <id>`** halts a pulse - a queued one never starts - **`/halt <module>`** (or a planned row's id) halts a
|
|
255
|
-
module's planned pulses until you ask for it again, a spec change not starting it, and **`/halt activated <name>`**
|
|
256
|
-
halts a server `activate` started; it lists all three when no id is given.
|
|
257
|
-
- **What these commands show you, the chat knows.** What `/regenerate` and `/halt activated` tell you - a spec that
|
|
258
|
-
does not parse, the pulses planned, a server halted - stays in the chat under the command, and since a slash command
|
|
259
|
-
runs outside the conversation, it is put in the conversation as well: say "fix it" next and turri knows what you are
|
|
260
|
-
looking at. A halted pulse reaches it as every pulse's end does.
|
|
261
|
-
- **Nothing is queued.** What is left to build is worked out from what each codebase is built from
|
|
262
|
-
and the spec as it is now - again whenever a pulse ends or the spec changes - and the first pulse of
|
|
263
|
-
it runs; see [a whole module](regenerating.md#a-whole-module). Changes that overlap never pile up: the next pulse
|
|
264
|
-
builds the spec as it is. The pulses planned after the one running are listed behind it, as queued,
|
|
265
|
-
and so is each module waiting for the one it is built on - "waits for base" - until it can be planned.
|
|
266
|
-
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
|
|
267
|
-
in the spec: the codebase waits until the spec changes or it is asked for again.
|
|
268
|
-
- **A change to a module below** is made in the codebase at the tip of the chain, where its code
|
|
269
|
-
lives; the codebase below is left as it was, and is brought up to its own spec only when a new
|
|
270
|
-
module is to start from it. Specs moved into a module the code was not built on stop the codebase:
|
|
271
|
-
no change to its code brings that module in, so it has to be started over - its code and
|
|
272
|
-
conformance tests taken out, kept in its history, and built again from the bottom of the chain.
|
|
273
|
-
That is never done unasked: the chat asks you, saying why, and regenerates it from scratch once you agree;
|
|
274
|
-
on the command line `turri regenerate` asks at the terminal, and `--start-over` agrees in advance.
|
|
275
|
-
- **Conformance tests are a track of their own.** A code pulse lands once its unit tests pass and are
|
|
276
|
-
reviewed. Then, before the next one builds on it, a conformance pulse writes and runs the tests of what it
|
|
277
|
-
built - from the test reqs and acceptance tests - with the whole suite the module inherits, and, where one
|
|
278
|
-
fails, fixes the test or the code, whichever is wrong; what they are written for is recorded in
|
|
279
|
-
`tests/.turri.json`. With `conformance-tests: false` none is written until you ask -
|
|
280
|
-
`conform`, for a module or some of its functional specs. A conformance pulse that does not pass
|
|
281
|
-
is undone whole and halts the conformance tests alone: the code goes on being built.
|
|
282
|
-
- **A pulse that fails** - its work errors, or it does not pass - is run once more. Failing again, it
|
|
283
|
-
stops, and so does every pulse queued behind it on the same module, without running - the other
|
|
284
|
-
modules' pulses go on. The harness then works out why: an
|
|
285
|
-
agent that can read the project's specs, code, tests, testing scripts and logs, and turri's
|
|
286
|
-
own source, skills and rules, says what happened, why, whether the fix belongs in the spec, the
|
|
287
|
-
environment, the code or turri itself, and exactly what to do.
|
|
288
|
-
- **When a pulse finishes** the transcript shows its line - `✓`, `✗` or `■`, its module, kind and number,
|
|
289
|
-
how long it took and what it cost, never what it regenerated -
|
|
290
|
-
`✓ shorty · conformance pulse 4 finished after 3m 47s · 488.6k tok · $0.02` - and the chat, which
|
|
291
|
-
gets its whole report, reacts then and there, whatever else is running or queued, without waiting
|
|
292
|
-
for you to speak: at once when it is idle, else as soon as the reply it is in ends. It does what the
|
|
293
|
-
project's guidance says to do when a pulse finishes - release what was built, say - or tells you
|
|
294
|
-
what finished and what it means. Ask to try it ("let me try it") and the chat releases what is
|
|
295
|
-
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,
|
|
296
|
-
whatever else is running or queued, without waiting for you to speak - at once when it is idle, else
|
|
297
|
-
as soon as the reply it is in ends: it does what the project's guidance says to do when a pulse
|
|
298
|
-
finishes (release what was built, say), or tells you in a line or two what finished.
|
|
299
|
-
- **When a pulse stops** - a gate still failing after 20 attempts - it says where it stopped, why in
|
|
300
|
-
plain words, and what to change in the spec - which section, and how.
|
|
301
|
-
Running the same build again picks up from there.
|
|
302
|
-
|
|
303
|
-
In `print`, `json` and `rpc` modes the process ends when the answer is written, so the tools wait
|
|
304
|
-
for the work there instead. Pulses live in memory for the session; the work itself is on disk.
|
|
75
|
+
`◇` and `◆` are both green, and mean the same whatever `conformance-tests:` says: a functional spec regenerated and not conformed is `◇` with its conformance tests on, off or not chosen, so changing the setting changes no mark. Tests written for an earlier text leave it at `◇`. Definitions and reqs are never conformed: `◇` is as far as they go. Test reqs are shown only where conformance tests are on - `conformance-tests:` is not `false`, or `conform` turned them on this session. A test req is the conformance tests', never built into the code: `◆` once they follow it as it reads now, the green `⠋` while a conformance pulse writes them for it, `○` until then - and no mark where no conformance test is written at all. No pulse numbers are drawn in the gutter - they move whenever the plan is made again; `p` on an item goes to the pulse that brings it.
|
|
76
|
+
|
|
77
|
+
**Needs you.** The top line ends `! needs you`, in red, and under the first `!` of the module is what for, and how: `needs you - pulse 3 didn't land - its unit tests never passed · d to talk it through in the chat`. `d` closes the panel and asks the chat, in your words, what went wrong and what to do about it, with turri's reason for the halt; the chat works it out with you - a diagnosis, a change to the spec, the machine set up - and regenerates. Pulses are numbered as they start in a module, from 1 each session.
|
|
78
|
+
|
|
79
|
+
A changed item shows what changed in it: its first line word by word - what is gone struck through in red, 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 out is simply gone. The top line has a strip of the module's functional specs - built, regenerating, planned, waiting - and how many are built, then what is happening: `pulse 3 of 8 regenerating`, or why nothing is - `not asked to build - regenerate plans it` (turri was just opened, or nothing has asked for the module: the plan lives in memory and is made again on the next regeneration), `planning`, `waits for backend`, or `! needs you`. `enter` opens an item: all of its text against the code's, and its acceptance tests. Where it stands is beside its mark, and is not said again under it.
|
|
80
|
+
|
|
81
|
+
One module is shown at a time, with a tab for each module of the chain on the line under the top line, in the chain's order - the module it is built on to the left: `d365_version_api [d365_http_client] d365_utils 12 ›`. A tab regenerating spins, one stuck says `!`; what does not fit is counted at either end. `←` `→` go from one tab to the next. The module shown is the one in focus - the one regenerating now, else the one asked for, else the first - until you pick another tab; it goes back to following once another module is in focus, or the one in focus starts regenerating. Under the module's own text is what it imports, under **imported**, a folded block a file, `▸ from stdlib/backend/python-fastapi · 7 reqs · all built`, closed until opened. The modules it requires are tabs of their own: a chain of many modules is never drawn nested, one in the next. A map longer than the screen has a minimap down its right edge, a cell a slice in the colour of its most pressing mark, the slice shown solid. The map is read from the files - the code record, the `.plain` files, the tests record - so it is right the moment turri opens a project, before anything runs; the work loop's plan adds the pulses on top. It maps the files asked to build this conversation, else `module:` in `config.turri.yaml`, else the `.plain` files of the folder that no other one there imports or requires - the folder's files looked at again only once one of them, or its config, changes. `↑` `↓` move row by row, `enter` or `space` open and close an item or an import block - a functional spec opens to its sub-bullets and its `***acceptance tests***`, nested under it as the spec has them - `←` `→` go to the next module's tab, `o` and `c` open or close everything shown, `pgup` `pgdn` and the wheel scroll, `g`/`G` go to the top and the bottom.
|
|
82
|
+
|
|
83
|
+
`p` goes to the **pulses** - and back - onto the pulse that regenerates the item under the cursor, and 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 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 finished one's mark green when it passed, red when it failed or did not pass, amber when it was stopped. Opened, a running one shows what it is doing; a queued one, what it waits for; a finished one, its agents and what each spent, and whether it did not pass. Under it is a row for each file its spec diff changes - the file of the module being rendered first and open, the rest by name and closed - each opening onto that file's lines. A file with nothing added or taken out is not listed. `↑` `↓` move, `enter` or `space` open and close what is under the cursor, `→` `←` open and close (`←` on a closed pulse goes to its section, on a closed file to its pulse), `o` and `c` open or close every pulse of the section - or, on a file, every file of its pulse - `pgup` `pgdn` and the wheel scroll, `g`/`G` go to the top and the bottom. The cursor stays on its row when the pulse under it moves on; a pulse opened closes when it moves to another section. What is open is kept while the panel is closed. What the agents said and did is not shown - it is in each pulse's log (see [Agent logs](#agent-logs)).
|
|
84
|
+
|
|
85
|
+
`ctrl+h` again, or `esc`, closes it and goes back to the chat. Beside the chat, one side has the keys and the other is drawn faint: `ctrl+h` switches sides - from the chat to the panel, from the panel to the chat, the panel staying and following the pulses - `esc` gives the chat the keys too, and a click gives them to the side clicked. `ctrl+c` closes the panel; so do `s`, over the whole screen, then `esc`. (pi's regular screen, `--tui-mode regular`, reads no mouse: there it is the keys alone.) While the panel has the keys, every key is the panel's, whatever else happens: a question the chat model asks in the background (`ask_user`) waits in the chat, unanswered - an `enter` in the panel never answers it - and the panel's top line says "the chat is waiting for your answer". Back in the chat, the question is there, with the keys.
|
|
86
|
+
- `turri` runs pi in fullscreen mode, so the conversation stays where you scroll it while the pulses redraw (PgUp/PgDn, the wheel); `--tui-mode regular` goes back to the terminal's own scrollback.
|
|
87
|
+
- **`/turri-config`** changes a setting of the project's `config.turri.yaml` - the models, review, conformance tests, any key - and says when it takes effect: now, at your next message, or at the next pulse; never only after a restart. See [changing it from the chat](config.md#changing-it-from-the-chat).
|
|
88
|
+
- **`/stack`** chooses the stack everything is built with from then on, in a project whose parts are on different stacks: a list of the project's stacks, or `/stack backend`, `/stack none`. The stack's `config.turri.<stack>.yaml` is laid over `config.turri.yaml` - its testing scripts, toolchains, models - for the session; a pulse already running keeps the stack it started with. The chat model switches it too when you ask. See [stacks](config.md#stacks).
|
|
89
|
+
- **`/regenerate [module | file.plain] [functionality ...] [from scratch [whole chain]] [how to cut the work]`** regenerates a module from its spec as it is now, as the `regenerate` tool does: what is left to regenerate is planned into pulses - one functional spec at a time, a few together or the whole module in one, as the planner judges - and the first starts. Words after the module are guidance for that plan (`/regenerate app models first`). A module's name typed with spaces for its underscores is that module - `/regenerate d365_function executor` is `d365_function_executor`. With no module named: the one `module:` in `config.turri.yaml` names, else the folder's top modules, to pick from. Asked for from scratch - `from scratch`, `start over`, `delete the module` - it asks first, then deletes the module's code and conformance tests in every codebase where they live, committed so `/lineage` keeps them, and regenerates the whole module from its spec, built though nothing in it changed: `/regenerate shorty from scratch`. The modules below it keep their code, and the module starts again from a copy of the code below it. Asked for its chain too - `/regenerate shorty from scratch, the whole chain` - the code of every module of its requires chain is deleted, the base's included, and the whole chain is regenerated from the bottom: what to do after modules were split, merged or moved, when the code below was laid out for modules that are no more. The chat's `regenerate` does the same with `from_scratch: "module"` or `"chain"`, when you ask for it; `turri regenerate --from-scratch` or `--from-scratch-chain` on the command line, not with `--dry-run`. Functionalities named after the module - `/regenerate shorty 3 5` - are regenerated though their spec did not change, on the model chosen for functionalities: as `turri regenerate shorty.plain 3 5` does, and the chat's `regenerate` with `functionalities`.
|
|
90
|
+
- **`/halt <id>`** halts a pulse - a queued one never starts - **`/halt <module>`** (or a planned row's id) halts a module's planned pulses until you ask for it again, a spec change not starting it, and **`/halt activated <name>`** halts a server `activate` started; it lists all three when no id is given.
|
|
91
|
+
- **What these commands show you, the chat knows.** What `/regenerate` and `/halt activated` tell you - a spec that does not parse, the pulses planned, a server halted - stays in the chat under the command, and since a slash command runs outside the conversation, it is put in the conversation as well: say "fix it" next and turri knows what you are looking at. A halted pulse reaches it as every pulse's end does.
|
|
92
|
+
- **Nothing is queued.** What is left to build is worked out from what each codebase is built from and the spec as it is now - again whenever a pulse ends or the spec changes - and the first pulse of it runs; see [a whole module](regenerating.md#a-whole-module). Changes that overlap never pile up: the next pulse builds the spec as it is. The pulses planned after the one running are listed behind it, as queued, and so is each module waiting for the one it is built on - "waits for base" - until it can be planned. 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 in the spec: the codebase waits until the spec changes or it is asked for again.
|
|
93
|
+
- **A change to a module below** is made in the codebase at the tip of the chain, where its code lives; the codebase below is left as it was, and is brought up to its own spec only when a new module is to start from it. Specs moved into a module the code was not built on stop the codebase: no change to its code brings that module in, so it has to be started over - its code and conformance tests taken out, kept in its history, and built again from the bottom of the chain. That is never done unasked: the chat asks you, saying why, and regenerates it from scratch once you agree; on the command line `turri regenerate` asks at the terminal, and `--start-over` agrees in advance.
|
|
94
|
+
- **Conformance tests are a track of their own.** A code pulse lands once its unit tests pass and are reviewed. Then, before the next one builds on it, a conformance pulse writes and runs the tests of what it built - from the test reqs and acceptance tests - with the whole suite the module inherits, and, where one fails, fixes the test or the code, whichever is wrong; what they are written for is recorded in `tests/.turri.json`. With `conformance-tests: false` none is written until you ask - `conform`, for a module or some of its functional specs. A conformance pulse that does not pass is undone whole and halts the conformance tests alone: the code goes on being built.
|
|
95
|
+
- **A pulse that fails** - its work errors, or it does not pass - is run once more. Failing again, it stops, and so does every pulse queued behind it on the same module, without running - the other modules' pulses go on. The harness then works out why: an agent that can read the project's specs, code, tests, testing scripts and logs, and turri's own source, skills and rules, says what happened, why, whether the fix belongs in the spec, the environment, the code or turri itself, and exactly what to do.
|
|
96
|
+
- **When a pulse finishes** the transcript shows its line - `✓`, `✗` or `■`, its module, kind and number, how long it took and what it cost, never what it regenerated - `✓ shorty · conformance pulse 4 finished after 3m 47s · 488.6k tok · $0.02` - and the chat, which gets its whole report, reacts then and there, whatever else is running or queued, without waiting for you to speak: at once when it is idle, else as soon as the reply it is in ends. It does what the project's guidance says to do when a pulse finishes - release what was built, say - or tells you what finished and what it means. Ask to try it ("let me try it") and the chat releases what is 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, whatever else is running or queued, without waiting for you to speak - at once when it is idle, else as soon as the reply it is in ends: it does what the project's guidance says to do when a pulse finishes (release what was built, say), or tells you in a line or two what finished.
|
|
97
|
+
- **When a pulse stops** - a gate still failing after 20 attempts - it says where it stopped, why in plain words, and what to change in the spec - which section, and how. Running the same build again picks up from there.
|
|
98
|
+
|
|
99
|
+
In `print`, `json` and `rpc` modes the process ends when the answer is written, so the tools wait for the work there instead. Pulses live in memory for the session; the work itself is on disk.
|
|
305
100
|
|
|
306
101
|
## The project's config.turri.yaml
|
|
307
102
|
|
|
308
|
-
The chat reads the project's `config.turri.yaml` afresh every turn and follows it: its agent is told what
|
|
309
|
-
it sets, and the render tools default to it - `module` when you ask to build without naming one,
|
|
310
|
-
`conformance-tests: false` to render without conformance tests (none written, none of the existing
|
|
311
|
-
ones run) unless you ask for them, `coding-model` for what renders run on, and the testing scripts.
|
|
312
|
-
`harness-model` is what `turri` starts on. What you ask for in the conversation wins.
|
|
313
|
-
Every key, what happens without it, and how the models inherit: [the project config](config.md).
|
|
103
|
+
The chat reads the project's `config.turri.yaml` afresh every turn and follows it: its agent is told what it sets, and the render tools default to it - `module` when you ask to build without naming one, `conformance-tests: false` to render without conformance tests (none written, none of the existing ones run) unless you ask for them, `coding-model` for what renders run on, and the testing scripts. `harness-model` is what `turri` starts on. What you ask for in the conversation wins. Every key, what happens without it, and how the models inherit: [the project config](config.md).
|
|
314
104
|
|
|
315
|
-
A project whose parts are on different stacks gives each stack its own `config.turri.<stack>.yaml`
|
|
316
|
-
beside `config.turri.yaml` - `config.turri.backend.yaml`, `config.turri.frontend.yaml` - with its
|
|
317
|
-
testing scripts, models and conformance over the project's. A stack is chosen, never worked out:
|
|
318
|
-
`/stack backend` before building the backend, `/stack frontend` before the frontend, and every render
|
|
319
|
-
from then on follows the chosen one's; the chat is told each stack's and which is chosen, and the status
|
|
320
|
-
bar shows it. See [stacks](config.md#stacks).
|
|
105
|
+
A project whose parts are on different stacks gives each stack its own `config.turri.<stack>.yaml` beside `config.turri.yaml` - `config.turri.backend.yaml`, `config.turri.frontend.yaml` - with its testing scripts, models and conformance over the project's. A stack is chosen, never worked out: `/stack backend` before building the backend, `/stack frontend` before the frontend, and every render from then on follows the chosen one's; the chat is told each stack's and which is chosen, and the status bar shows it. See [stacks](config.md#stacks).
|
|
321
106
|
|
|
322
|
-
A project with only a `config.yaml` - turri's file before it had its own name, or another tool's - is
|
|
323
|
-
read from it until turri first writes a setting, which copies it to `config.turri.yaml`; see
|
|
324
|
-
[the old config.yaml](config.md#the-old-configyaml).
|
|
107
|
+
A project with only a `config.yaml` - turri's file before it had its own name, or another tool's - is read from it until turri first writes a setting, which copies it to `config.turri.yaml`; see [the old config.yaml](config.md#the-old-configyaml).
|
|
325
108
|
|
|
326
109
|
## Choosing a model
|
|
327
110
|
|
|
328
|
-
There are three: the **harness model**, the one you chat with; the **coding model**, the one
|
|
329
|
-
every render runs on - functionalities, conformance tests, repairs, spec changes; and the **judge
|
|
330
|
-
model**, which gives the verdicts in a conformance run - the judge, which says whether the code, the
|
|
331
|
-
tests or the spec is wrong, and the test review. The project's `config.turri.yaml` can give each a model and
|
|
332
|
-
a thinking level (off, minimal, low, medium, high, xhigh, max):
|
|
111
|
+
There are three: the **harness model**, the one you chat with; the **coding model**, the one every render runs on - functionalities, conformance tests, repairs, spec changes; and the **judge model**, which gives the verdicts in a conformance run - the judge, which says whether the code, the tests or the spec is wrong, and the test review. The project's `config.turri.yaml` can give each a model and a thinking level (off, minimal, low, medium, high, xhigh, max):
|
|
333
112
|
|
|
334
113
|
```yaml
|
|
335
114
|
harness-model:
|
|
@@ -342,20 +121,11 @@ judge-model:
|
|
|
342
121
|
model: anthropic/claude-opus-5-5
|
|
343
122
|
```
|
|
344
123
|
|
|
345
|
-
Each may leave out either part, and a bare string (`coding-model: provider/id`, or
|
|
346
|
-
`provider/id:high`) is a model alone. What one leaves out it takes from the one it inherits from:
|
|
347
|
-
the judge model from the coding model, the coding model from the harness model - so with only a
|
|
348
|
-
harness model, everything runs on it.
|
|
124
|
+
Each may leave out either part, and a bare string (`coding-model: provider/id`, or `provider/id:high`) is a model alone. What one leaves out it takes from the one it inherits from: the judge model from the coding model, the coding model from the harness model - so with only a harness model, everything runs on it.
|
|
349
125
|
|
|
350
|
-
On the command line, `turri --harness-model <m> --coding-model <m>` wins over them
|
|
351
|
-
(pi's own `--model` works for the harness model too), and in the conversation pi's `/model`
|
|
352
|
-
changes the harness model and `engine`, below, the coding model. `model:`, from before
|
|
353
|
-
there were two, is read as `coding-model`. With neither, renders run on the conversation's model.
|
|
126
|
+
On the command line, `turri --harness-model <m> --coding-model <m>` wins over them (pi's own `--model` works for the harness model too), and in the conversation pi's `/model` changes the harness model and `engine`, below, the coding model. `model:`, from before there were two, is read as `coding-model`. With neither, renders run on the conversation's model.
|
|
354
127
|
|
|
355
|
-
Every render runs on the coding model unless you say otherwise. Say it in words -
|
|
356
|
-
"render spec changes with gpt 5.5", "build the functionalities on Gemini 3.6 Flash", "use Claude
|
|
357
|
-
for everything" - and the agent calls `engine`, which holds for the rest of the session
|
|
358
|
-
(a resumed one too):
|
|
128
|
+
Every render runs on the coding model unless you say otherwise. Say it in words - "render spec changes with gpt 5.5", "build the functionalities on Gemini 3.6 Flash", "use Claude for everything" - and the agent calls `engine`, which holds for the rest of the session (a resumed one too):
|
|
359
129
|
|
|
360
130
|
| kind of work | covers |
|
|
361
131
|
| --- | --- |
|
|
@@ -363,25 +133,11 @@ for everything" - and the agent calls `engine`, which holds for the rest of the
|
|
|
363
133
|
| functionalities | render functionality, render module, regenerate, conformance |
|
|
364
134
|
| everything | both |
|
|
365
135
|
|
|
366
|
-
It works mid-interview as well: the skill's agent has the same tool. Pulses already queued keep the
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
Names are resolved strictly, because pi's own matching guesses and says nothing ("gpt-5" can land
|
|
372
|
-
on a Bedrock model you have no key for). An exact `provider/model-id` is taken as it is. A looser
|
|
373
|
-
name is taken when it fits exactly one model you have credentials for, or is exactly one model's
|
|
374
|
-
id in other words ("gpt 5.5" is `openai/gpt-5.5`, not `gpt-5.5-pro`). Anything else comes back as
|
|
375
|
-
a short list and the agent asks you which one; a model whose provider has no credentials is never
|
|
376
|
-
picked.
|
|
377
|
-
|
|
378
|
-
A provider a pi extension registers - your company's own LLM gateway, say - works for every agent
|
|
379
|
-
the conversation starts, not only for the conversation. Those agents load no extensions (they would
|
|
380
|
-
load a second copy of turri), so each is given the providers the conversation's extensions
|
|
381
|
-
registered, as they are when it starts. An unattended run - `turri regenerate`, `render` and the
|
|
382
|
-
rest, outside the chat - has no conversation to take them from: there, only the providers in pi's
|
|
383
|
-
own configuration (`~/.pi/agent/models.json` and `auth.json`) are there, so a gateway those runs use
|
|
384
|
-
has to be set up in `models.json`.
|
|
136
|
+
It works mid-interview as well: the skill's agent has the same tool. Pulses already queued keep the model they were queued with; `"chat"` drops the session's choice, back to the default coding model - `--coding-model`, `config.turri.yaml`, or the conversation's. `/engine` shows what each kind of work runs on. A render tool can also be given a model for one call.
|
|
137
|
+
|
|
138
|
+
Names are resolved strictly, because pi's own matching guesses and says nothing ("gpt-5" can land on a Bedrock model you have no key for). An exact `provider/model-id` is taken as it is. A looser name is taken when it fits exactly one model you have credentials for, or is exactly one model's id in other words ("gpt 5.5" is `openai/gpt-5.5`, not `gpt-5.5-pro`). Anything else comes back as a short list and the agent asks you which one; a model whose provider has no credentials is never picked.
|
|
139
|
+
|
|
140
|
+
A provider a pi extension registers - your company's own LLM gateway, say - works for every agent the conversation starts, not only for the conversation. Those agents load no extensions (they would load a second copy of turri), so each is given the providers the conversation's extensions registered, as they are when it starts. An unattended run - `turri regenerate`, `render` and the rest, outside the chat - has no conversation to take them from: there, only the providers in pi's own configuration (`~/.pi/agent/models.json` and `auth.json`) are there, so a gateway those runs use has to be set up in `models.json`.
|
|
385
141
|
|
|
386
142
|
To change pi's own default, in `~/.pi/agent/settings.json`:
|
|
387
143
|
|
|
@@ -389,21 +145,13 @@ To change pi's own default, in `~/.pi/agent/settings.json`:
|
|
|
389
145
|
{ "defaultProvider": "google", "defaultModel": "gemini-3.1-pro-preview" }
|
|
390
146
|
```
|
|
391
147
|
|
|
392
|
-
A provider failure - no credits, bad key, rate limit - is raised with the provider's own message,
|
|
393
|
-
rather than surfacing as an agent that said nothing.
|
|
148
|
+
A provider failure - no credits, bad key, rate limit - is raised with the provider's own message, rather than surfacing as an agent that said nothing. One that passes - overloaded, rate limited, unreachable, timed out - is waited out first, after pi's own retries: six more tries, the wait doubled each time from 15 seconds up to five minutes (15s, 30s, 1m, 2m, 4m, 5m, a tenth either way so parallel jobs do not all come back at once), the agent carrying on where it was. Each wait - pi's own retries too - is shown as it happens - a notification in the chat and the job panel's status, an orange line in a headless run - and listed in the run report's `turn_incidents`. So is a provider stalling: a request to the model that nothing has come back on for two minutes (`TURRI_PROVIDER_STALL`, in seconds; 0 never), said once for each silence while the turn goes on waiting. A turn turri stops itself - its time up, the agent going round in a circle - is the work's normal course and is not said, only listed.
|
|
394
149
|
|
|
395
150
|
## Module history
|
|
396
151
|
|
|
397
|
-
Each `plain_modules/<module>` is a git repository whose git directory is `.plaingit` rather than
|
|
398
|
-
`.git`, so it stays plain files to your own repository. A commit is made after every step that
|
|
399
|
-
changes the module - a render, a functionality regenerated, a conformance run, a regression repair, a spec
|
|
400
|
-
change. `/lineage [module]` and `lineage` show it.
|
|
152
|
+
Each `plain_modules/<module>` is a git repository whose git directory is `.plaingit` rather than `.git`, so it stays plain files to your own repository. A commit is made after every step that changes the module - a render, a functionality regenerated, a conformance run, a regression repair, a spec change. `/lineage [module]` and `lineage` show it.
|
|
401
153
|
|
|
402
|
-
The last commit is also the last known good state. Every render, functionality regenerated, spec change and
|
|
403
|
-
conformance run starts by putting the codebase it works in back to it, so if turri was
|
|
404
|
-
stopped or restarted mid-pulse, whatever that pulse left half-written is undone first - and one that
|
|
405
|
-
does not pass is undone the same way when it ends, commits and all. Only work that passed is
|
|
406
|
-
committed. Installed dependencies and caches are not in the history and stay. With git directly:
|
|
154
|
+
The last commit is also the last known good state. Every render, functionality regenerated, spec change and conformance run starts by putting the codebase it works in back to it, so if turri was stopped or restarted mid-pulse, whatever that pulse left half-written is undone first - and one that does not pass is undone the same way when it ends, commits and all. Only work that passed is committed. Installed dependencies and caches are not in the history and stay. With git directly:
|
|
407
155
|
|
|
408
156
|
```bash
|
|
409
157
|
git --git-dir=plain_modules/<module>/.plaingit --work-tree=plain_modules/<module> log
|
|
@@ -411,40 +159,18 @@ git --git-dir=plain_modules/<module>/.plaingit --work-tree=plain_modules/<module
|
|
|
411
159
|
|
|
412
160
|
## Agent logs
|
|
413
161
|
|
|
414
|
-
When an agent does something you cannot explain, its logs are where to look: the chat shows what
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
whole
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
tools and its system prompt, and then has, in order and stamped with the time: every prompt it is
|
|
423
|
-
sent, whole; its thinking and replies as they stream; every tool call with its arguments, numbered
|
|
424
|
-
- `→ #3 bash` - and its whole result under the same number, `← #3 bash done`, since calls made
|
|
425
|
-
together run at once and finish in any order; a tool call a response was cut off in, marked as
|
|
426
|
-
never run; each response's stop reason, tokens and cost; the provider's
|
|
427
|
-
retries and errors; and how each turn ended. Every line is on disk as it happens, so
|
|
428
|
-
`tail -f` follows an agent live and a run that crashed leaves its log up to that moment. The pulse's
|
|
429
|
-
own log names each agent's log as it starts.
|
|
430
|
-
|
|
431
|
-
Beside them, each pulse has a log of its own in `.turri/jobs/` - `<time>-<pulse id>-<kind>.log`:
|
|
432
|
-
its whole transcript, written as it happens. The harness's stages, the functional spec or the
|
|
433
|
-
diff it builds, and every one of its agents in turn - each prompt, its thinking and replies, every
|
|
434
|
-
tool call and its result, whole where the screen clips them - and how the pulse ended. A finished pulse,
|
|
435
|
-
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
|
|
436
|
-
prompt, tokens and retries besides.
|
|
437
|
-
|
|
438
|
-
No agent can read the logs: they are outside `plain_modules` - or, for a `--build-dir` outside it,
|
|
439
|
-
beside that folder rather than in it. Nothing prunes them either - delete
|
|
440
|
-
the folder when you are done with it. A log that cannot be written is given up on without failing
|
|
441
|
-
the render.
|
|
162
|
+
When an agent does something you cannot explain, its logs are where to look: the chat shows what its pulse is doing, not what its agents said. Every agent a render starts - the coding agent, the conformance agent, the repair agent, the spec-steps planner - also streams its whole conversation to a file of its own, always.
|
|
163
|
+
|
|
164
|
+
The logs are in `.turri/debug/` in the project, beside `plain_modules`, one per agent, named by when it started and what it is: `2026-09-26T13-45-02-123Z-app-3-coding-agent.log`. Each starts with the pulse it runs for, its model and thinking level, its folder, its saved pi session, its tools and its system prompt, and then has, in order and stamped with the time: every prompt it is sent, whole; its thinking and replies as they stream; every tool call with its arguments, numbered
|
|
165
|
+
- `→ #3 bash` - and its whole result under the same number, `← #3 bash done`, since calls made together run at once and finish in any order; a tool call a response was cut off in, marked as never run; each response's stop reason, tokens and cost; the provider's retries and errors; and how each turn ended. Every line is on disk as it happens, so `tail -f` follows an agent live and a run that crashed leaves its log up to that moment. The pulse's own log names each agent's log as it starts.
|
|
166
|
+
|
|
167
|
+
Beside them, each pulse has a log of its own in `.turri/jobs/` - `<time>-<pulse id>-<kind>.log`: its whole transcript, written as it happens. The harness's stages, the functional spec or the diff it builds, and every one of its agents in turn - each prompt, its thinking and replies, every tool call and its result, whole where the screen clips them - and how the pulse ended. A finished pulse, 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 prompt, tokens and retries besides.
|
|
168
|
+
|
|
169
|
+
No agent can read the logs: they are outside `plain_modules` - or, for a `--build-dir` outside it, beside that folder rather than in it. Nothing prunes them either - delete the folder when you are done with it. A log that cannot be written is given up on without failing the render.
|
|
442
170
|
|
|
443
171
|
## From the command line
|
|
444
172
|
|
|
445
|
-
The same work, without a conversation. Run it from the directory that holds the spec, so its
|
|
446
|
-
linked resources resolve the way the parser expects. For a long run - a whole spec overnight - see
|
|
447
|
-
[running unattended](headless.md).
|
|
173
|
+
The same work, without a conversation. Run it from the directory that holds the spec, so its linked resources resolve the way the parser expects. For a long run - a whole spec overnight - see [running unattended](headless.md).
|
|
448
174
|
|
|
449
175
|
```bash
|
|
450
176
|
turri validate <file.plain> # validate a spec - no model, no API key
|
|
@@ -453,6 +179,7 @@ turri regenerate <file.plain> # regenerate what the code is not bui
|
|
|
453
179
|
turri glimpse <file.plain> # plan it, and print the first job's prompt - starts nothing
|
|
454
180
|
turri regenerate <file.plain> 2 # regenerate functionality 2 again, changed or not
|
|
455
181
|
turri regenerate <file.plain> --from-scratch # delete the module's code and tests (its lineage keeps them), regenerate all of it
|
|
182
|
+
turri regenerate <file.plain> --from-scratch-chain # the same for every module of its requires chain, from the bottom
|
|
456
183
|
turri spec-diff <file.plain> <diff> # apply a spec diff, and regenerate it
|
|
457
184
|
turri conform <file.plain> 1 # black-box tests for functionality 1
|
|
458
185
|
turri lineage <module> # what each regeneration changed in a module, and when
|
|
@@ -460,7 +187,4 @@ turri cultivate brood # run a skill directly - by name, the pro
|
|
|
460
187
|
turri release <file.plain> # release what is regenerated to dist/<module>, and activate it here
|
|
461
188
|
```
|
|
462
189
|
|
|
463
|
-
The ones that build take `--model provider/model-id`; `regenerate` also takes `--build-dir` and
|
|
464
|
-
`--dry-run`, which plans the work, prints the prompt of each codebase's first pulse and starts nothing.
|
|
465
|
-
Template directories come from `PLAIN_TEMPLATE_DIRS`. `--help`
|
|
466
|
-
on any of them lists the rest.
|
|
190
|
+
The ones that build take `--model provider/model-id`; `regenerate` also takes `--build-dir` and `--dry-run`, which plans the work, prints the prompt of each codebase's first pulse and starts nothing. Template directories come from `PLAIN_TEMPLATE_DIRS`. `--help` on any of them lists the rest.
|