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