@turri-dev/cli 0.1.11-next.be75b46 → 0.1.11

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/README.md CHANGED
@@ -10,11 +10,11 @@
10
10
 
11
11
  **turri** is named after *Turritopsis dohrnii*, the immortal jellyfish that regenerates itself from its young form, again and again - as **turri** regenerates the code from the durable intent - see [the name](#the-name).
12
12
 
13
- **turri** has a desktop app too: [turri-app](https://github.com/turri-oss/turri-app).
13
+ **turri** has a desktop app too: [turri desktop](https://github.com/turri-oss/turri-desktop).
14
14
 
15
15
  ## Quick start
16
16
 
17
- **turri** is built on [pi](https://pi.dev), the coding agent, and runs wherever pi runs: macOS, Linux, WSL; native Windows best effort, with Git Bash. You need git, bash and [Node](https://nodejs.org/en/download) 22.19 or newer - a Linux distribution's own `nodejs` package is often older. The agents use this machine's toolchains, fenced by a command check and an audit everywhere, and an OS sandbox where the OS has one - Seatbelt on macOS, bubblewrap on Linux (`apt install bubblewrap`) - see [installation](docs/installation.md#installation).
17
+ **turri** is built on [pi](https://pi.dev), the coding agent, and runs wherever [pi](https://pi.dev) runs: macOS, Linux, WSL; native Windows best effort, with Git Bash. You need git, bash and [Node](https://nodejs.org/en/download) 22.19 or newer - a Linux distribution's own `nodejs` package is often older. The agents use this machine's toolchains, fenced by a command check and an audit everywhere, and an OS sandbox where the OS has one - Seatbelt on macOS, bubblewrap on Linux (`apt install bubblewrap`) - see [installation](docs/installation.md#installation).
18
18
 
19
19
  ```bash
20
20
  npm install -g @turri-dev/cli # puts `turri` on your PATH
@@ -23,7 +23,7 @@ turri doctor # checks the machine
23
23
 
24
24
  To follow `main` as it moves, or work on turri itself, run it [from a clone](#from-a-clone) instead.
25
25
 
26
- `doctor` checks for Node 22.19+, bash, the OS sandbox and a model provider for pi; in a project, the toolchains its modules need, what its testing scripts run against this machine, and that each model `config.turri.yaml` names answers with your credentials. It changes nothing without asking: when a check fails - the OS sandbox does not start, say - it says why, and the command for you to run. Run it again whenever something breaks. What each check means: [installation](docs/installation.md).
26
+ `doctor` checks for Node 22.19+, bash, the OS sandbox and a model provider for [pi](https://pi.dev); in a project, the toolchains its modules need, what its testing scripts run against this machine, and that each model `config.turri.yaml` names answers with your credentials. It changes nothing without asking: when a check fails - the OS sandbox does not start, say - it says why, and the command for you to run. Run it again whenever something breaks. What each check means: [installation](docs/installation.md).
27
27
 
28
28
  Then start it in your project, signed in to your model providers:
29
29
 
@@ -101,7 +101,7 @@ With **turri** you work on the durable intent. You say what the software must do
101
101
 
102
102
  ## How it works
103
103
 
104
- **turri** captures the durable intent in [\*\*\*plain](https://plainlang.org/), a language for saying what software should do. \*\*\*plain breaks the intent down into functionalities - small units, each a single thing the software does - and **turri** regenerates the code from them piece by piece.
104
+ **turri** captures the durable intent in [\*\*\*plain](https://plainlang.org/docs/), a language for saying what software should do. \*\*\*plain breaks the intent down into functionalities - small units, each a single thing the software does - and **turri** regenerates the code from them piece by piece.
105
105
 
106
106
  1. **Define.** You say what the software should do; **turri** writes it down as \*\*\*plain.
107
107
  2. **Review and refine.** You review \*\*\*plain and change it with **turri** until it says what you mean.
@@ -127,7 +127,7 @@ So the tools speak its language: **`regenerate`** regenerates the code from \*\*
127
127
 
128
128
  ## Models
129
129
 
130
- `init-config`'s models are only a starting point. **turri** is built on [pi](https://github.com/earendil-works/pi), so any model pi supports works - Anthropic, OpenAI, Google, Amazon Bedrock, OpenRouter, a local one. A model is reached as pi reaches it - `/login`, in `turri` as in `pi`, the provider's API key in the environment (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, ...), or a cloud account - and named as pi names it, `provider/model-id`, with `:high`, `:low` and so on for how hard it thinks. It uses three: the **harness** model you talk to, which writes \*\*\*plain and plans the work - worth a capable one - and the **coding** and **judge** models its agents build and judge with, which can be smaller and cheaper, such as GPT-6 Luna or Gemini 3.1 Flash Lite. `turri --harness-model` and `--coding-model` choose them for a session, and pi's `/model` switches the one you talk to as you go; to keep them for the project, set them with `/turri-config harness-model`, `/turri-config coding-model` and so on - each role's too, as `models.<role>` - or write them in its `config.turri.yaml`:
130
+ `init-config`'s models are only a starting point. **turri** is built on [pi](https://pi.dev), so any model [pi](https://pi.dev) supports works - Anthropic, OpenAI, Google, Amazon Bedrock, OpenRouter, a local one. A model is reached as [pi](https://pi.dev) reaches it - `/login`, in `turri` as in `pi`, the provider's API key in the environment (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, ...), or a cloud account - and named as [pi](https://pi.dev) names it, `provider/model-id`, with `:high`, `:low` and so on for how hard it thinks. It uses three: the **harness** model you talk to, which writes \*\*\*plain and plans the work - worth a capable one - and the **coding** and **judge** models its agents build and judge with, which can be smaller and cheaper, such as GPT-6 Luna or Gemini 3.1 Flash Lite. `turri --harness-model` and `--coding-model` choose them for a session, and [pi](https://pi.dev)'s `/model` switches the one you talk to as you go; to keep them for the project, set them with `/turri-config harness-model`, `/turri-config coding-model` and so on - each role's too, as `models.<role>` - or write them in its `config.turri.yaml`:
131
131
 
132
132
  ```yaml
133
133
  harness-model: anthropic/claude-opus-5-5 # the model you talk to: a capable one
@@ -179,7 +179,7 @@ turri regenerate app.plain # regenerate the code from ***plain: planned int
179
179
  turri regenerate app.plain 3 # regenerate functionality 3, changed or not
180
180
  ```
181
181
 
182
- More: [using **turri**](docs/using.md); to render \*\*\*plain overnight, see [running unattended](docs/headless.md).
182
+ More: [using **turri**](docs/using.md); to regenerate \*\*\*plain overnight, see [running unattended](docs/headless.md).
183
183
 
184
184
  ## Documentation
185
185
 
@@ -192,7 +192,7 @@ Start at the [documentation index](docs/README.md), or go straight to a page:
192
192
  | [Using **turri**](docs/using.md) | the conversation, skills, tools, pulses and regen, choosing models, the command line |
193
193
  | [The project config](docs/config.md) | `config.turri.yaml` and each stack's `config.turri.<stack>.yaml`: every key, models and their inheritance, conformance, the testing scripts, stacks and choosing one, the old `config.yaml` |
194
194
  | [Deploy](docs/deploy.md) | trying what is built: the last commit in `dist/<module>`, started on your machine, nothing installed without asking |
195
- | [Running unattended](docs/headless.md) | rendering \*\*\*plain overnight or in CI: the command, keeping it running, the results, resuming, rebuilding one functionality |
195
+ | [Running unattended](docs/headless.md) | regenerating \*\*\*plain overnight or in CI: the command, keeping it running, the results, resuming, rebuilding one functionality |
196
196
  | [Authoring \*\*\*plain](docs/authoring-plain.md) | what \*\*\*plain is made of, the authoring rules, the skills that write and fix it, checking it |
197
197
  | [Regenerating](docs/regenerating.md) | what each build does and in which order: functionalities, modules, regeneration, changes to \*\*\*plain, conformance and acceptance tests, working notes, what the code is built from |
198
198
  | [The sandbox](docs/sandbox.md) | what agents can reach, the walls every command passes, time limits, the web tools |
@@ -4,9 +4,9 @@ import { checkPlainFile } from "./plain/check.js";
4
4
  import { applySpecDiff, revertSpecDiff } from "./regenerate/regenerate.js";
5
5
  import { parseArgs } from "./cli-options.js";
6
6
  import { headlessOptions, runLoop } from "./loop-cli.js";
7
- const USAGE = `usage: turri spec-diff <file.plain> <diff-file> [options]
7
+ const USAGE = `usage: turri change-plain <file.plain> <diff-file> [options]
8
8
 
9
- Applies a change to the specs, given as a git diff of the .plain files, and builds it: the headless
9
+ Applies a change to ***plain, given as a git diff of the .plain files, and builds it: the headless
10
10
  counterpart of regenerate, given a diff. The diff is applied first, unless it is already in; then, as
11
11
  turri regenerate does, what is left to build is planned into jobs and built.
12
12
 
@@ -40,7 +40,7 @@ runLoop({
40
40
  startOver: options["start-over"] !== undefined,
41
41
  ...(buildDir !== undefined ? { buildDir } : {}),
42
42
  ...(report !== undefined ? { report } : {}),
43
- command: ["spec-diff", ...process.argv.slice(2)],
43
+ command: ["change-plain", ...process.argv.slice(2)],
44
44
  ask: (loop) => loop.bringUp(plainFile),
45
45
  }).catch((error) => {
46
46
  console.error(error instanceof Error ? error.message : error);
package/dist/cli.js CHANGED
@@ -78,7 +78,7 @@ const COMMANDS = {
78
78
  glimpse: { module: "./regenerate-cli.ts", blurb: "plan the work and print the first job's prompt, starting nothing", args: ["--dry-run"] },
79
79
  drift: { module: "./drift-cli.ts", blurb: "what is left to regenerate: how far the code has drifted from its spec" },
80
80
  conform: { module: "./conform-cli.ts", blurb: "write and run a module's conformance tests" },
81
- "spec-diff": { module: "./spec-diff-cli.ts", blurb: "apply a change to the specs, given as a git diff, and regenerate it" },
81
+ "change-plain": { module: "./change-plain-cli.ts", blurb: "apply a change to ***plain, given as a git diff, and regenerate it" },
82
82
  validate: { module: "./validate-cli.ts", blurb: "validate a ***plain spec, regenerating nothing" },
83
83
  lineage: { module: "./lineage-cli.ts", blurb: "a module's lineage: what was regenerated into it, and when" },
84
84
  ledger: { module: "./ledger-cli.ts", blurb: "what turri did here: the last runs and their pulses, or one pulse, from the ledger" },
package/dist/extension.js CHANGED
@@ -669,11 +669,11 @@ function turriExtension(pi, host) {
669
669
  : "It changed no file in the project - whatever it said it wrote is not there. Say so to the user; do not report the work as done.";
670
670
  // A skill that edits the specs with the file tools builds nothing: the change is the conversation's to render.
671
671
  const specsChanged = changes.filter((path) => path.endsWith(".plain"));
672
- const unrendered = specsChanged.length > 0 && !skill.allowedTools.includes("write_spec_diff")
672
+ const unrendered = specsChanged.length > 0 && !skill.allowedTools.includes("change_plain")
673
673
  ? `${specsChanged.join(", ")} changed, and nothing is regenerated from that yet: call regenerate for it, and the code is brought up to the spec.`
674
674
  : "";
675
675
  const gated = skill.steps.some((step) => step.gate !== undefined);
676
- const first = skill.allowedTools.includes("write_spec_diff") ? firstRegeneration(jobs.list(), began) : {};
676
+ const first = skill.allowedTools.includes("change_plain") ? firstRegeneration(jobs.list(), began) : {};
677
677
  const ttfr = first.started === undefined
678
678
  ? ""
679
679
  : `Time to first regeneration: ${formatElapsed(first.started)} - its first pulse started that long after ${skill.name} began` +
@@ -1125,7 +1125,7 @@ export function projectConfigBlock(root) {
1125
1125
  return [
1126
1126
  ...settings(readProjectConfig(dir), withStack(undefined, () => findTestScripts(dir)), dir === root ? `${projectConfigFile(dir)}, for the specs here:` : `${relative(root, dir)}/${projectConfigFile(dir)}, for the specs in ${relative(root, dir)}/ - built in ${relative(root, dir)}/plain_modules:`, where, stacks.length > 0 ? "project of stacks" : "project"),
1127
1127
  ...(stacks.length > 0
1128
- ? ["", `Stacks: ${stacks.join(", ")} - chosen now: ${chosen ?? "none, so the project's file alone"}. Each module is built with the stack of its part, pinned to its pulses whatever is chosen after: a stack named after the module is its own - backend.plain is built with config.turri.backend.yaml - with nothing to choose. For a module whose stack has another name, pass it as stack to regenerate, conform, glimpse and write_spec_diff. Choose one for the whole session with the stack tool only when the user asks.`]
1128
+ ? ["", `Stacks: ${stacks.join(", ")} - chosen now: ${chosen ?? "none, so the project's file alone"}. Each module is built with the stack of its part, pinned to its pulses whatever is chosen after: a stack named after the module is its own - backend.plain is built with config.turri.backend.yaml - with nothing to choose. For a module whose stack has another name, pass it as stack to regenerate, conform, glimpse and change_plain. Choose one for the whole session with the stack tool only when the user asks.`]
1129
1129
  : []),
1130
1130
  // A stack: its file over the project's, for everything built while it is chosen.
1131
1131
  ...stacks.flatMap((stack) => [
@@ -1298,7 +1298,7 @@ function setRenderModelTool(pi, conversation) {
1298
1298
  label: "Engine",
1299
1299
  description: "The engine: which model the agents that regenerate the code run on. With no model, say which it is. With one, choose it " +
1300
1300
  "for the rest of this session: for spec changes " +
1301
- "(render spec diff pulses, and the ones write_spec_diff queues), for functionalities (render, module, " +
1301
+ "(render spec diff pulses, and the ones change_plain queues), for functionalities (render, module, " +
1302
1302
  "regenerate with functionalities named, conformance), or for everything. By default " +
1303
1303
  "each runs on the model the project's config.turri.yaml names, or else the conversation's model. The model may be given as provider/model-id or by name as " +
1304
1304
  "the user said it; a name that fits more than one model, or none with credentials, comes back as a " +
package/dist/genome.js CHANGED
@@ -12,7 +12,7 @@ import { DISMISSED } from "./ask.js";
12
12
  import { createQuestioning, levelOf, questioningQuestion } from "./questioning.js";
13
13
  import { createSpecDiffTools } from "./spec-tools.js";
14
14
  import { createMatureTools, MATURE_TOOLS } from "./mature-tools.js";
15
- const WRITE_SPEC_DIFF = "write_spec_diff";
15
+ const CHANGE_PLAIN = "change_plain";
16
16
  /** The conversation's tools a skill acts on the work loop with - never pi built-ins. */
17
17
  const LOOP_TOOLS = ["regenerate", "drift", "halt", "conform"];
18
18
  /** How much of what the agent said before a question is shown with it: its end, where the brief is. */
@@ -77,14 +77,14 @@ export async function runSkill(opts) {
77
77
  const questions = {
78
78
  refusal: (confirmsPhase) => diffPerAnswer() && diffs?.pace.owed() === true
79
79
  ? "This question was not asked: the last answer is not in the spec yet. Every answer in this phase is a spec " +
80
- "change, built at once - write it with write_spec_diff first, then ask."
80
+ "change, built at once - write it with change_plain first, then ask."
81
81
  : questioning?.refusal(confirmsPhase),
82
82
  answered: (confirmsPhase) => questioning?.answered(confirmsPhase),
83
83
  end: () => questioning?.end() ?? "No questioning level was chosen: ask what the phase needs.",
84
84
  };
85
- // A skill whose unit of work is a spec change gets write_spec_diff: the change is applied
85
+ // A skill whose unit of work is a spec change gets change_plain: the change is applied
86
86
  // and its build queued in one step.
87
- const diffs = opts.renderQueue !== undefined && skill.allowedTools.includes(WRITE_SPEC_DIFF)
87
+ const diffs = opts.renderQueue !== undefined && skill.allowedTools.includes(CHANGE_PLAIN)
88
88
  ? createSpecDiffTools({
89
89
  loop: opts.renderQueue,
90
90
  cwd: opts.cwd,
@@ -125,7 +125,7 @@ export async function runSkill(opts) {
125
125
  customTools.push(...(opts.sharedTools ?? []));
126
126
  const names = customTools.map((tool) => tool.name);
127
127
  // Tools this harness provides are never pi built-ins, even when it did not provide them.
128
- const builtins = skill.allowedTools.filter((t) => !names.includes(t) && t !== WRITE_SPEC_DIFF && !MATURE_TOOLS.includes(t) && !LOOP_TOOLS.includes(t));
128
+ const builtins = skill.allowedTools.filter((t) => !names.includes(t) && t !== CHANGE_PLAIN && !MATURE_TOOLS.includes(t) && !LOOP_TOOLS.includes(t));
129
129
  const executor = await createExecutor({
130
130
  cwd: opts.cwd,
131
131
  customTools,
package/dist/identity.js CHANGED
@@ -27,8 +27,9 @@ export function conversationIdentity(surface) {
27
27
  }
28
28
  const IDENTITY_BEFORE = [
29
29
  "<turri>",
30
- "You are turri - always lowercase - a coding agent with the power of regenerative software. The software is its",
31
- "***plain; the code is regenerated from it. You help the person write ***plain, and you regenerate the code from it a",
30
+ "You are turri - always lowercase - the first coding agent with the power of regenerative software. The software is",
31
+ "its ***plain; the code is regenerated from it. You write the ***plain with the person - they say what the software",
32
+ "should do, and you write it down as ***plain, shaping it with them - and you regenerate the code from it a",
32
33
  "change at a time - with agents that write the code and tests, while you decide what runs next and when the work is",
33
34
  "done - record what each piece was regenerated from, and prove it against conformance tests written from the ***plain",
34
35
  "alone. When the code goes bad, you regenerate it from the ***plain. You are named after Turritopsis dohrnii, the",
@@ -37,9 +38,10 @@ const IDENTITY_BEFORE = [
37
38
  "gone bad is regenerated from it, whole, rather than patched. Say it as that likeness, not as a fact about a",
38
39
  "jellyfish.",
39
40
  "",
40
- "Asked who or what you are, say it in those words: you are turri, a coding agent with the power of regenerative",
41
- "software - you help them write ***plain and regenerate the code from it. Not an assistant, and not a helper with",
42
- "specifications: ***plain is the language they write, and naming it is the point. Your replies are Markdown, where",
41
+ "Asked who or what you are, say it in those words: you are turri, the first coding agent with the power of",
42
+ "regenerative software - you write ***plain with them and regenerate the code from it. Never say they write the",
43
+ "***plain and you help: you write it, together. Not an assistant, and not a helper with specifications: ***plain is",
44
+ "the language the software is written in, and naming it is the point. Your replies are Markdown, where",
43
45
  "three asterisks start bold italics: write the name escaped, \\*\\*\\*plain, so it shows as ***plain.",
44
46
  "",
45
47
  "Speak as turri, in the first person - I, my pulses, my agents - to the person, in whole sentences. Never speak of",
@@ -53,7 +55,7 @@ const IDENTITY_BEFORE = [
53
55
  " allow-to-stop-jobs in config.turri.yaml are about pulses. \"Job\" in what you read is a pulse; say pulse.",
54
56
  ];
55
57
  const IDENTITY_AFTER = [
56
- "- mutate, in a skill's activity, is write_spec_diff: a spec change written and regenerated in one step.",
58
+ "- mutate, in a skill's activity, is change_plain: a spec change written and regenerated in one step.",
57
59
  "- Regenerate is the word for what you do to the code: never grow, grew or grown - older text, a tool's description",
58
60
  " or a report may still say it, and means regenerate.",
59
61
  ];
@@ -1,7 +1,7 @@
1
1
  import { type DriftReport, type ModuleStatus, type WorkLoop } from "./regenerate/loop.ts";
2
2
  import { type ModuleState } from "./run-report.ts";
3
3
  /**
4
- * What every command that builds - `turri regenerate`, `conform`, `spec-diff` - does around its own
4
+ * What every command that builds - `turri regenerate`, `conform`, `change-plain` - does around its own
5
5
  * request of the work loop, as the chat does it: the project's models, a job that fails run once more and, failing again,
6
6
  * diagnosed, a line as each job starts and ends; then the loop run until nothing more can start, how each job ended,
7
7
  * and exit 1 when any failed or a module is not complete. With `dryRun`, the work is planned and the prompt of the first job each codebase would
package/dist/loop-cli.js CHANGED
@@ -17,7 +17,7 @@ import { listFiles } from "./regenerate/testing.js";
17
17
  import { startRunReport } from "./run-report.js";
18
18
  import { configKeyOptions, optionValue } from "./cli-options.js";
19
19
  /**
20
- * What every command that builds - `turri regenerate`, `conform`, `spec-diff` - does around its own
20
+ * What every command that builds - `turri regenerate`, `conform`, `change-plain` - does around its own
21
21
  * request of the work loop, as the chat does it: the project's models, a job that fails run once more and, failing again,
22
22
  * diagnosed, a line as each job starts and ends; then the loop run until nothing more can start, how each job ended,
23
23
  * and exit 1 when any failed or a module is not complete. With `dryRun`, the work is planned and the prompt of the first job each codebase would
@@ -173,10 +173,10 @@ export function withinModules(text) {
173
173
  }
174
174
  /**
175
175
  * What the person is shown a tool as, where that is not the name its agent calls it by. The agent's name says
176
- * what the call takes - `write_spec_diff` takes a diff of the spec - and the shown one speaks turri's language.
176
+ * what the call takes - `change_plain` takes a diff of the spec - and the shown one speaks turri's language.
177
177
  */
178
178
  const SHOWN_AS = {
179
- write_spec_diff: "mutate",
179
+ change_plain: "mutate",
180
180
  };
181
181
  /** A tool's name as the person is shown it. */
182
182
  export function shownName(name) {
@@ -15,7 +15,7 @@ const TOOL_FOR = {
15
15
  conform: "conform",
16
16
  cultivate: "cultivate",
17
17
  release: "release",
18
- "spec-diff": "regenerate",
18
+ "change-plain": "regenerate",
19
19
  chat: "nothing - you are the conversation already",
20
20
  ask: "nothing - you are the conversation already",
21
21
  };
@@ -31,7 +31,7 @@ const NPM_SCRIPT = {
31
31
  const ENTRY = {
32
32
  "regenerate-cli": "regenerate",
33
33
  "conform-cli": "conform",
34
- "spec-diff-cli": "spec-diff",
34
+ "change-plain-cli": "change-plain",
35
35
  "cultivate-cli": "cultivate",
36
36
  "release-cli": "release",
37
37
  };
@@ -43,10 +43,10 @@ const AT_COMMAND = String.raw `(?:^|[\s;&|()\x60$])`;
43
43
  * agent - and neither are setup and doctor.
44
44
  */
45
45
  export function selfInvocation(command) {
46
- const cli = new RegExp(`${AT_COMMAND}(?:npx\\s+)?turri\\s+(regenerate|glimpse|conform|cultivate|release|spec-diff)\\b`).exec(command);
46
+ const cli = new RegExp(`${AT_COMMAND}(?:npx\\s+)?turri\\s+(regenerate|glimpse|conform|cultivate|release|change-plain)\\b`).exec(command);
47
47
  if (cli)
48
48
  return cli[1];
49
- const launcher = new RegExp(`(?:bin/turri\\.mjs|src/cli\\.ts)\\s+(regenerate|glimpse|conform|cultivate|release|spec-diff)\\b`).exec(command);
49
+ const launcher = new RegExp(`(?:bin/turri\\.mjs|src/cli\\.ts)\\s+(regenerate|glimpse|conform|cultivate|release|change-plain)\\b`).exec(command);
50
50
  if (launcher)
51
51
  return launcher[1];
52
52
  // turri alone, or with options, is the conversation - where a command starts, not a word an argument names (`which turri`).
@@ -83,7 +83,7 @@ const PI_CONFIGURES = new Set([
83
83
  export function askedForCommandLine(message) {
84
84
  const text = message.toLowerCase();
85
85
  return (/\b(headless|command[ -]line|cli|terminal|shell|in bash|via bash|through bash|npm run|nohup)\b/.test(text) ||
86
- /\bturri\s+(regenerate|glimpse|conform|spec-diff|cultivate|release)\b/.test(text) ||
86
+ /\bturri\s+(regenerate|glimpse|conform|change-plain|cultivate|release)\b/.test(text) ||
87
87
  /(^|\s)turri\s+-p\b/.test(text) ||
88
88
  /(^|\s)pi\s+-p\b/.test(text));
89
89
  }
@@ -102,7 +102,7 @@ export const TOOLS_NOT_CLI = [
102
102
  "<turri-tools>",
103
103
  "In this conversation, you do your work with your tools - regenerate, conform, cultivate and the rest - which run as",
104
104
  "background jobs the user can watch and halt. To try what is regenerated, release it - never by hand in plain_modules. Never",
105
- "run your own command line (turri regenerate, glimpse, conform, spec-diff, cultivate, release, turri itself; npm run",
105
+ "run your own command line (turri regenerate, glimpse, conform, change-plain, cultivate, release, turri itself; npm run",
106
106
  "regenerate and the like) or start another pi through bash:",
107
107
  "that is a separate headless run the user cannot see or stop. Only when the user explicitly asks for the",
108
108
  "command line, run it. Configuring pi itself - pi install, update, list, config, auth, or its settings files -",
package/dist/skill.d.ts CHANGED
@@ -70,7 +70,7 @@ export interface Skill {
70
70
  allowedTools: string[];
71
71
  steps: StepSpec[];
72
72
  /**
73
- * Whether `write_spec_diff` needs an answer from the user between two new changes - one answer,
73
+ * Whether `change_plain` needs an answer from the user between two new changes - one answer,
74
74
  * one change, as an interview writes them. `metadata.paced: false` turns it off, for a skill that
75
75
  * writes the specs on its own.
76
76
  */
@@ -81,8 +81,8 @@ export interface Skill {
81
81
  */
82
82
  questioning: string[];
83
83
  /**
84
- * The steps where each answer is a spec change (`metadata.spec-diff-per-answer`): the next question waits until the
85
- * last answer is written with `write_spec_diff`, and changes the agent decides itself need no answer before them.
84
+ * The steps where each answer is a spec change (`metadata.change-plain-per-answer`): the next question waits until the
85
+ * last answer is written with `change_plain`, and changes the agent decides itself need no answer before them.
86
86
  */
87
87
  diffPerAnswer: string[];
88
88
  /**
package/dist/skill.js CHANGED
@@ -109,11 +109,11 @@ export function loadSkill(skillDir) {
109
109
  throw new Error(`${name}: 'metadata.questioning' names unknown step '${stepName}'`);
110
110
  }
111
111
  }
112
- const perAnswer = data.metadata?.["spec-diff-per-answer"];
112
+ const perAnswer = data.metadata?.["change-plain-per-answer"];
113
113
  const diffPerAnswer = Array.isArray(perAnswer) ? perAnswer.map(String) : [];
114
114
  for (const stepName of diffPerAnswer) {
115
115
  if (!steps.some((s) => s.name === stepName)) {
116
- throw new Error(`${name}: 'metadata.spec-diff-per-answer' names unknown step '${stepName}'`);
116
+ throw new Error(`${name}: 'metadata.change-plain-per-answer' names unknown step '${stepName}'`);
117
117
  }
118
118
  }
119
119
  for (const stepName of gatesByStep.keys()) {
@@ -28,7 +28,7 @@ export function createSpecDiffTools(options) {
28
28
  let owed = false;
29
29
  let answeredSinceLastDiff = true;
30
30
  const writeDiff = defineTool({
31
- name: "write_spec_diff",
31
+ name: "change_plain",
32
32
  label: "Write spec diff",
33
33
  description: "Apply a change to the ***plain specs, given as a git diff of the .plain files, and start building it in " +
34
34
  "the background. The diff is applied with git; if the specs no longer parse, it is undone and nothing is " +
@@ -36,7 +36,7 @@ export function createSpecDiffTools(options) {
36
36
  "every change is built, whatever it touches.",
37
37
  promptSnippet: "apply a git diff of the .plain specs and start building it",
38
38
  promptGuidelines: [
39
- "Every change to a .plain file in the product phase goes through write_spec_diff, as a git diff with paths relative to the project root. It writes the change and starts its build in one step.",
39
+ "Every change to a .plain file in the product phase goes through change_plain, as a git diff with paths relative to the project root. It writes the change and starts its build in one step.",
40
40
  skillPaced
41
41
  ? "One change per answer, and a new one only after the user has answered a question about it. Set fixes_earlier to correct something already written."
42
42
  : "Write the changes one after another, on your own: no answer is needed between them, and none is asked for. Set fixes_earlier to correct something already written.",
package/dist/stacks.js CHANGED
@@ -77,7 +77,7 @@ export function registerStacks(pi, cwd) {
77
77
  "For the session; a pulse already running keeps the stack it started with. Without a name, says the stacks and the one chosen.",
78
78
  promptSnippet: "choose the stack - its testing scripts and settings - that everything is built with",
79
79
  promptGuidelines: [
80
- "Switch the stack only when the user asks for it, and say which you chose. A module is built with the stack named after it by itself; to build one whose stack has another name, pass that stack as stack to regenerate, conform, glimpse or write_spec_diff instead: it is pinned to that module's pulses, and the session's choice stays as it is.",
80
+ "Switch the stack only when the user asks for it, and say which you chose. A module is built with the stack named after it by itself; to build one whose stack has another name, pass that stack as stack to regenerate, conform, glimpse or change_plain instead: it is pinned to that module's pulses, and the session's choice stays as it is.",
81
81
  ],
82
82
  parameters: Type.Object({
83
83
  name: Type.Optional(Type.String({ description: "The stack to choose, or none. Omitted: the stacks there are, and the one chosen" })),
package/dist/tools.js CHANGED
@@ -164,7 +164,7 @@ export function createEndQuestionsTool(questioning) {
164
164
  label: "End questions",
165
165
  description: "End this phase's questions: you have asked what the person must decide, and you decide what is left " +
166
166
  "yourself, saying what you chose. Afterwards ask_user asks only the phase's closing confirmation, and " +
167
- "write_spec_diff needs no answer between changes.",
167
+ "change_plain needs no answer between changes.",
168
168
  promptSnippet: "end this phase's questions and decide what is left yourself",
169
169
  parameters: Type.Object({}),
170
170
  async execute() {
package/docs/README.md CHANGED
@@ -1,31 +1,31 @@
1
1
  # turri documentation
2
2
 
3
- turri implements regenerative software: the \*\*\*plain specs are the durable definition of what a system does, and the code is generated from them, validated against them, and regenerated as they change. The [project README](../README.md) says why, and how to install and start; these pages go into each part.
3
+ turri is the first coding agent with the power of regenerative software: [\*\*\*plain](https://plainlang.org/docs/) captures the durable definition of what a system does, and the code is regenerated from it and validated against. The [project README](../README.md) says why, and how to install and start; these pages go into each part.
4
4
 
5
5
  ## Start here
6
6
 
7
7
  1. [Installation](installation.md) - get a machine ready: `turri doctor`, and what turri needs of this machine.
8
- 2. [Using turri](using.md) - the conversation, the skills and tools, background jobs and their logs, choosing the model that renders, the command line.
9
- 3. [Authoring \*\*\*plain](authoring-plain.md) - writing the specs: what a spec is made of, the authoring rules, the skills that write and fix specs.
10
- 4. [Rendering](regenerating.md) - turning the specs into code: what each build does, in which order, and what has to pass before it moves on.
8
+ 2. [Using turri](using.md) - the conversation, the skills and tools, background jobs and their logs, choosing the model that codes, the command line.
9
+ 3. [Authoring \*\*\*plain](authoring-plain.md) - writing \*\*\*plain: what is it made out of, the authoring rules, the skills that write and fix it.
10
+ 4. [Regenerating](regenerating.md) - turning \*\*\*plain into code: what each build does, in which order, and what has to pass before it moves on.
11
11
 
12
12
  ## By question
13
13
 
14
14
  | to find out… | read |
15
15
  | --- | --- |
16
16
  | what my machine needs, and why a check failed | [installation](installation.md) |
17
- | what turri needs of this machine, and what `turri doctor` checks | [installation](installation.md#what-turri-setup-checks) |
17
+ | what turri needs of this machine, and what `turri doctor` checks | [installation](installation.md#what-turri-doctor-checks) |
18
18
  | how to start a project, or add a feature, in a conversation | [using](using.md#in-a-conversation) |
19
- | which model renders, and how to change it | [using](using.md#choosing-a-model), [the project config](config.md#models) |
19
+ | which model codes, and how to change it | [using](using.md#choosing-a-model), [the project config](config.md#models) |
20
20
  | what `config.turri.yaml` can set, and what happens without it | [the project config](config.md) |
21
21
  | how a backend and a frontend on different stacks share one project | [the project config](config.md#stacks) |
22
- | which ready-made stacks a spec can import - a FastAPI backend, a React frontend | [the standard library](authoring-plain.md#the-standard-library) |
22
+ | which ready-made stacks \*\*\*plain can import - a FastAPI backend, a React frontend | [the standard library](authoring-plain.md#the-standard-library) |
23
23
  | everything an agent was sent and did, to debug it | [using](using.md#agent-logs) |
24
- | how to render a spec overnight, and resume it | [running unattended](headless.md) |
24
+ | how to regenerate \*\*\*plain overnight, and resume it | [running unattended](headless.md) |
25
25
  | how to rebuild one functionality | [running unattended](headless.md#rebuilding-one-functionality) |
26
- | what goes in which section of a spec | [authoring \*\*\*plain](authoring-plain.md#what-a-spec-is-made-of) |
26
+ | what goes in which section of \*\*\*plain | [authoring \*\*\*plain](authoring-plain.md#what-plain-is-made-of) |
27
27
  | which skill does what | [authoring \*\*\*plain](authoring-plain.md#the-skills) |
28
- | what happens when a spec changes | [regenerating the code](regenerating.md#when-the-spec-changes) |
28
+ | what happens when \*\*\*plain changes | [regenerating the code](regenerating.md#when-plain-changes) |
29
29
  | why a test was not allowed to be deleted | [regenerating the code](regenerating.md#the-tests-must-actually-pass) |
30
30
  | how to try what is built, and what deploy may install | [deploy](deploy.md) |
31
31
  | what the agents can and cannot reach | [the sandbox](sandbox.md) |
@@ -42,9 +42,9 @@ turri implements regenerative software: the \*\*\*plain specs are the durable de
42
42
  | [Using turri](using.md) | the conversation, the tools, background jobs, choosing a model, module history, the command line |
43
43
  | [The project config](config.md) | `config.turri.yaml` and each stack's `config.turri.<stack>.yaml`: where they are read from, every key, models and their inheritance, conformance, the testing scripts, stacks and choosing one, the old `config.yaml` |
44
44
  | [Deploy](deploy.md) | trying what is built: dist/<module>, the last commit, starting it on your machine, `turri release` |
45
- | [Running unattended](headless.md) | rendering overnight or in CI: before you leave it, the command, the results, resuming, rebuilding one functionality |
46
- | [Authoring \*\*\*plain](authoring-plain.md) | a \*\*\*plain project, what a spec is made of, the rules, writing specs with the agent, the skills, checking a spec |
47
- | [Rendering](regenerating.md) | where things go, one job, a whole module and how its work is cut into jobs, each job's cases, spec changes, conformance tests, the two records of what is built |
45
+ | [Running unattended](headless.md) | regenerating overnight or in CI: before you leave it, the command, the results, resuming, rebuilding one functionality |
46
+ | [Authoring \*\*\*plain](authoring-plain.md) | a \*\*\*plain project, what \*\*\*plain is made of, the rules, writing \*\*\*plain with the agent, the skills, checking \*\*\*plain |
47
+ | [Regenerating](regenerating.md) | where things go, one job, a whole module and how its work is cut into jobs, each job's cases, \*\*\*plain changes, conformance tests, the two records of what is built |
48
48
  | [The sandbox](sandbox.md) | what an agent can reach, the file-tool fence, the command check, the OS sandbox, the audit |
49
49
  | [Skills and gates](skills-and-gates.md) | the gate syntax, what the harness enforces, what a step can do, the rules, trying the gates |
50
50
  | [The \*\*\*plain parser](parser.md) | the TypeScript port, `turri validate`, inheritance, the iterator, fidelity |