@turri-dev/cli 0.1.28-next.d5f2680 → 0.2.1-next.bc56a0d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +3 -2
  2. package/dist/chats.d.ts +31 -4
  3. package/dist/chats.js +146 -52
  4. package/dist/cli.js +4 -2
  5. package/dist/config.d.ts +4 -1
  6. package/dist/config.js +39 -4
  7. package/dist/environment.d.ts +0 -2
  8. package/dist/environment.js +0 -6
  9. package/dist/extension.d.ts +4 -3
  10. package/dist/extension.js +109 -22
  11. package/dist/host-session.d.ts +14 -0
  12. package/dist/host-session.js +2 -0
  13. package/dist/host.d.ts +6 -1
  14. package/dist/host.js +5 -1
  15. package/dist/init-config.d.ts +1 -1
  16. package/dist/init-config.js +33 -3
  17. package/dist/installed-providers.d.ts +40 -0
  18. package/dist/installed-providers.js +98 -0
  19. package/dist/model-check.d.ts +4 -2
  20. package/dist/model-check.js +33 -17
  21. package/dist/notice.d.ts +30 -6
  22. package/dist/pi.js +8 -24
  23. package/dist/plain/files.d.ts +16 -0
  24. package/dist/plain/files.js +68 -5
  25. package/dist/plain/graph.js +2 -2
  26. package/dist/plain/module-concepts.js +3 -2
  27. package/dist/plain/parser.d.ts +8 -3
  28. package/dist/plain/parser.js +47 -6
  29. package/dist/plain/stdlib.js +3 -3
  30. package/dist/regenerate/base-folder.d.ts +2 -0
  31. package/dist/regenerate/base-folder.js +24 -6
  32. package/dist/regenerate/command-check.d.ts +12 -1
  33. package/dist/regenerate/command-check.js +74 -0
  34. package/dist/regenerate/confine.d.ts +5 -0
  35. package/dist/regenerate/confine.js +9 -9
  36. package/dist/regenerate/ledger.d.ts +7 -0
  37. package/dist/regenerate/lineage.js +43 -2
  38. package/dist/regenerate/loop.d.ts +8 -0
  39. package/dist/regenerate/loop.js +11 -4
  40. package/dist/regenerate/os-sandbox.d.ts +2 -0
  41. package/dist/regenerate/os-sandbox.js +55 -20
  42. package/dist/regenerate/release.d.ts +2 -0
  43. package/dist/regenerate/requires.d.ts +12 -0
  44. package/dist/regenerate/requires.js +70 -1
  45. package/dist/regenerate/spec-steps.js +18 -1
  46. package/dist/regenerate/standing.d.ts +28 -0
  47. package/dist/regenerate/standing.js +30 -0
  48. package/dist/regenerate/testing.d.ts +2 -0
  49. package/dist/regenerate/testing.js +14 -0
  50. package/dist/release-agent.d.ts +17 -0
  51. package/dist/release-agent.js +19 -7
  52. package/dist/release-tools.d.ts +6 -0
  53. package/dist/release-tools.js +24 -5
  54. package/dist/sentinel-chat.d.ts +1 -1
  55. package/dist/sentinel-chat.js +21 -8
  56. package/dist/sentinel-check.d.ts +36 -0
  57. package/dist/sentinel-check.js +78 -0
  58. package/dist/sentinel.d.ts +40 -9
  59. package/dist/sentinel.js +240 -37
  60. package/dist/setup.d.ts +24 -3
  61. package/dist/setup.js +117 -31
  62. package/dist/spawn-async.d.ts +18 -0
  63. package/dist/spawn-async.js +35 -0
  64. package/dist/stack.d.ts +14 -0
  65. package/dist/stack.js +44 -2
  66. package/dist/turri-versions.d.ts +71 -0
  67. package/dist/turri-versions.js +275 -0
  68. package/docs/README.md +2 -0
  69. package/docs/claude-subscription.md +131 -0
  70. package/docs/config.md +5 -0
  71. package/docs/deploy.md +2 -2
  72. package/docs/hosting.md +42 -4
  73. package/docs/installation.md +39 -2
  74. package/docs/parser.md +1 -1
  75. package/docs/regenerating.md +1 -1
  76. package/docs/sandbox.md +2 -1
  77. package/docs/sentinel.md +11 -3
  78. package/docs/using.md +4 -2
  79. package/genome/rules/turri-regeneration.md +1 -1
  80. package/package.json +1 -1
@@ -6,9 +6,12 @@ The agents' commands run on this machine, with its toolchains - see [the sandbox
6
6
 
7
7
  ```bash
8
8
  npm install -g @turri-dev/cli # puts `turri` on your PATH
9
+ turri --version # the version just installed? - see below if not
9
10
  turri doctor # checks the machine: what turri needs, and what is missing
10
11
  ```
11
12
 
13
+ `turri --version` should say the version you just installed. If it says an older one - or the chat has commands this version does not, such as `/brood` - see [an older turri runs](#an-older-turri-runs).
14
+
12
15
  Then, in the project that holds your \*\*\*plain:
13
16
 
14
17
  ```bash
@@ -19,6 +22,39 @@ turri # pi, with turri's tools, skills and themes loaded
19
22
 
20
23
  The package is `@turri-dev/cli` - npm keeps the name `turri` back, as too like another package's - and the command it puts on your PATH is `turri`. `npm install -g @turri-dev/cli@next` gets the latest prerelease instead, built from the last commit on `main`. Installed again - `@latest` or `@next` - it replaces the one there. `turri --version` says which turri runs, and the [pi](https://pi.dev) under it: `turri 0.1.6 (pi 1.3.0)`, and from a clone its commit too.
21
24
 
25
+ ## An older turri runs
26
+
27
+ The install worked, and a bare `turri` still runs an older turri: another one comes before it on your PATH - installed under another Node version (nvm, fnm, volta and the like give each its own global folder), or an old `npm link` of a clone. The shell takes the first it finds.
28
+
29
+ 1. **See every turri there is.** `turri --version` lists each on your PATH, with its version, which one runs, and which is hidden - from turri 0.2.1 on. With an older turri in front, ask the shell:
30
+
31
+ ```bash
32
+ which -a turri # every turri on your PATH - the first is the one that runs
33
+ ls -l $(which -a turri) # where each really is: a Node version's folder, or a clone
34
+ ```
35
+
36
+ On Windows: `Get-Command turri -All` in PowerShell, or `where turri` in cmd - the first again the one that runs.
37
+
38
+ 2. **Run the new one now, before cleaning up:**
39
+
40
+ ```bash
41
+ "$(npm prefix -g)/bin/turri" # the turri npm just installed, by its path
42
+ npx @turri-dev/cli@latest # or the newest, whatever is on the PATH
43
+ ```
44
+
45
+ 3. **Take the old one off the PATH,** with the npm that put it there:
46
+
47
+ ```bash
48
+ nvm exec 22 npm uninstall -g @turri-dev/cli # one under another Node version of nvm - its version from the path
49
+ npm unlink -g @turri-dev/cli # an old npm link of a clone
50
+ ```
51
+
52
+ or delete the file `which -a turri` printed first. Then `hash -r`, or open a new terminal: the shell remembers where it last found `turri`. On Windows, nvm for Windows switches with `nvm use <version>` before the `npm uninstall`; then open a new terminal.
53
+
54
+ 4. **Check:** `turri --version` says the version you installed, and lists one turri on your PATH. `turri doctor` checks it too.
55
+
56
+ From 0.2.1 on, turri says so itself: its banner warns, as it starts, when a newer turri is out, or installed and hidden behind it - and `turri --version` and `turri doctor` say which turri is where, and what to run.
57
+
22
58
  ## From a clone
23
59
 
24
60
  To work on turri itself, put the clone on your PATH instead:
@@ -47,7 +83,8 @@ It checks, in order, and says exactly what to run for anything missing:
47
83
  | bash | every command an agent runs, and every testing script, runs with it | on Windows, Git for Windows; elsewhere, the system's package manager |
48
84
  | the OS sandbox | the wall under the command check and the audit | macOS has Seatbelt; on Linux, `apt install bubblewrap`. Where it does not start it says why and how to give it one - user namespaces off (Docker: a user that is not root, `--security-opt seccomp=unconfined`), AppArmor in the way (Docker: `--security-opt apparmor=unconfined`; Ubuntu 24.04: `sysctl -w kernel.apparmor_restrict_unprivileged_userns=0`), Docker's masked `/proc` (`--security-opt systempaths=unconfined`, or nothing: turri binds the container's `/proc` instead). Without one, the check and the audit hold alone |
49
85
  | a model provider | the agents need a model | run `pi` and `/login`, or set an API key (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, ...) |
50
- | `turri` on PATH | so it runs from any project | `npm install -g @turri-dev/cli`, or `npm link` in a clone |
86
+ | turri version | the newest turri npm has - asked as doctor runs; a turri from a clone is not compared | `npm install -g @turri-dev/cli@latest` |
87
+ | `turri` on PATH | so it runs from any project - and every turri on the PATH, with its version: an older one in front of a newer one is a problem, the newer one hidden behind it | `npm install -g @turri-dev/cli`, or `npm link` in a clone - and, for an older one in front, the command that takes it off, by where it is (another Node version of nvm, a linked clone, an npm prefix) |
51
88
  | turri and `pi` apart | `turri` starts [pi](https://pi.dev) with turri; a plain `pi` stays [pi](https://pi.dev) | an older `turri setup` wrote a file that loads turri into every `pi` - `doctor` offers to remove it |
52
89
 
53
90
  In a project - a folder with `config.turri.yaml` (or the old `config.yaml`) or `plain_modules` - it checks what the project needs of this machine too:
@@ -61,7 +98,7 @@ In a project - a folder with `config.turri.yaml` (or the old `config.yaml`) or `
61
98
 
62
99
  Removing that file is the one thing `doctor` changes, and it asks first; `turri doctor --yes` says yes. Run without a terminal - piped, or in CI - it asks nothing and changes nothing. Run it again whenever something breaks; `turri doctor --no-models` leaves out the models' requests. In the chat, ask for a self check: the `doctor` tool runs the same checks, the models only when you ask. A host - a desktop app - runs the same checks through `doctor` and shows them itself (see [doctor in a host](hosting.md#doctor-in-a-host)).
63
100
 
64
- The chat is told every turn which wall is up and what the project's modules need of this machine that it lacks. What they need is worked out from all the project's \*\*\*plain - seconds, on a project of long requires chains - so it is worked out once the chat is up and again after a turn in which \*\*\*plain changed, never while your message waits: a turn is told what was known last.
101
+ The chat is told every turn which wall is up and what the project's modules need of this machine that it lacks. What they need is worked out from all the project's \*\*\*plain - seconds, on a project of long requires chains - so it is worked out when the first turn asks - not as the chat opens - and again after a turn in which \*\*\*plain changed, never while your message waits: a turn is told what was known last.
65
102
 
66
103
  ## turri and `pi`
67
104
 
package/docs/parser.md CHANGED
@@ -113,7 +113,7 @@ for (const { funcId, specifications, codeVariables } of iterateFunctionalSpecs(t
113
113
 
114
114
  ## Parsing once
115
115
 
116
- A module's parse reads its imports and the whole of its `requires` chain, so a long chain asks for the same files over and over: bringing an 18-module chain up to its \*\*\*plain parsed for minutes. Two caches keep it to once. Inside `withParseCache`, one question about \*\*\*plain, each file is parsed once. Between calls, a parse is kept with a fingerprint of every file directly in its template folders and the current one - name, size, modification time, and a `.plain` file's text - and of every `.plain` file under the test folder, by name and text, and handed out again, as a copy, while the fingerprint is the same; \*\*\*plain that does not parse is kept as that too. A scenario written, changed or removed is seen at once. What a parse returns is unchanged: the cache only decides whether to parse again.
116
+ A module's parse reads its imports and the whole of its `requires` chain, so a long chain asks for the same files over and over: bringing an 18-module chain up to its \*\*\*plain parsed for minutes. Three caches keep it to once. Each file parsed on its own - a module, or a module it requires, read for what it requires and exports - is kept with every file it read: each file's text, and each file it looked for and did not find. It is handed out again while each is as it was: a file changed, an include changed, a module written in a folder looked in first, and it is parsed again. Inside `withParseCache`, one question about \*\*\*plain, each module is parsed once. Between calls, a parse is kept with a fingerprint of every file directly in its template folders and the current one - name, size, modification time, and a `.plain` file's text - and of every `.plain` file under the test folder, by name and text, and handed out again, as a copy, while the fingerprint is the same; \*\*\*plain that does not parse is kept as that too. A scenario written, changed or removed is seen at once. What a parse returns is unchanged: the cache only decides whether to parse again.
117
117
 
118
118
  ## Fidelity
119
119
 
@@ -276,7 +276,7 @@ A write the sandbox refused is told apart from a read - a report naming a lock f
276
276
  **The conversation heals it.** Told of the stop, it never regenerates the module again before the cause is fixed - a pulse stopped on its environment stops the same way again - and fixes what it can:
277
277
 
278
278
  - **hidden by the sandbox**: it adds the folder to `toolchains:` itself, says so in a line, and resumes - a refused write, which no setting fixes, it fixes in the project's own files when it can, and otherwise tells you what to do;
279
- - **a toolchain or a tool missing** - a JDK, Maven, Go, uv: it looks first for one installed off the PATH - Homebrew's opt folders, `/Library/Java/JavaVirtualMachines`, mise, asdf, sdkman, nvm - then asks you, with the exact command for this machine (`brew install openjdk@21`, `mise use -g java@21`), and on your yes runs it in its shell, checks the command is found now as the testing script would find it, and resumes. One installed where turri's own PATH does not reach needs turri restarted, and it says so. On a no - or where it cannot do it, sudo with a password, a licence - it tells you exactly what to do;
279
+ - **a toolchain or a tool missing** - a JDK, Maven, Go, uv, Node: turri installs nothing on your machine and changes none of its settings, asked or not - its shell refuses it. It looks first for one there after all: off the PATH - Homebrew's opt folders, `/Library/Java/JavaVirtualMachines`, mise, asdf, sdkman, nvm - or under another name, `python` where the testing script runs `python3`, of the version the \*\*\*plain names. Found, the testing script calling it as this machine has it is the fix: it changes the script, says so, and resumes. Not found, it tells you the exact command to run yourself (`brew install openjdk@21`, `mise use -g java@21`), and the line for your shell profile when the PATH needs it; "resume" picks it up once it is in. One installed where turri's own PATH does not reach needs turri restarted, and it says so. With the [sentinel](sentinel.md) on, it is the sentinel that fixes the script and resumes;
280
280
  - **a credential missing**: never made up - you are told where `agent-env:` reads it from.
281
281
 
282
282
  Either way the pulse is not tried again: no second run would find what is missing. The message is in the chat, at the end of `turri regenerate`, and in the job's log; after the fix the pulse runs again from the start. The re-run line names the \*\*\*plain description that was regenerated, as the folder it was run from reaches it.
package/docs/sandbox.md CHANGED
@@ -63,6 +63,7 @@ Before an agent's command runs, its text is checked (`src/regenerate/command-che
63
63
  - names a path outside the role's roots - absolute, a `..` that climbs out of the agent's folder (after the `cd`s before it), or inside a quoted string (`python3 -c "..."`). `~`, `$HOME` and `$TMPDIR` are the module's own and allowed, as are the package caches, the machine's system folders and the toolchains, and the devices (`/dev/null`). A path is checked when it names something on disk - under a top folder such as `/Users`, `/home`, `/etc` or `/tmp`, one of the fence's, or one that exists - so an API route in a curl or a JSON body is not one, and nor is `/` alone, a slash in code (`case '/':`), though writing to `/` is refused;
64
64
  - names the code record, `.turri.json`;
65
65
  - writes a credential file (`.env` and its variants; a template is fine) - by redirect, `tee`, `cp`, `mv` or an edit in place;
66
+ - changes a setting of the machine's or the person's environment: `defaults write`, `launchctl`, `systemctl enable`, `sysctl -w`, `git config --global`, `npm config set`, a line written to a shell profile (`~/.zshrc`) or `/etc`. The same rule (`machineChange`) holds in every shell turri runs, not only the agents': the chat's and the release agent's refuse an install or a system setting too, asked or not - turri changes nothing of the machine's;
66
67
  - installs software outside the project: `sudo`, the system's package managers installing (`brew`, `apt`, `dnf`, `apk`, `pacman`, `choco`, `winget`, ...), toolchain managers installing (`nvm`, `sdk`, `rustup`, `pyenv`, `asdf`, ...), global installs (`npm -g`, `yarn global`, `pip --user`, `pipx`, `gem install`), a script downloaded and run (`curl ... | sh`), an installer (`.pkg`, `.msi`, `.dmg`, `.run`). The project's own dependencies - `npm install`, pip into its venv, `mvn`, `cargo`, `go mod` - are building the code, and pass;
67
68
  - kills what its pulse did not start: `pkill`, `killall`, `taskkill`, `fuser -k`, or `kill` aimed at a port or name lookup. `kill $!` and `kill %1` pass.
68
69
 
@@ -99,7 +100,7 @@ DuckDuckGo is used without a key through its Lite page, which is not an official
99
100
 
100
101
  ## Outside the sandbox: deploy
101
102
 
102
- What `deploy` starts runs on your machine unfenced: you asked to try the software, with your toolchains, in your browser. It runs from `dist/<module>`, a copy of the last commit outside `plain_modules`, so no regenerating agent reaches it. Nothing is installed there without your say-so - every command that would install or download is put to you first, and the chat's shell refuses the rest. See [deploy](deploy.md).
103
+ What `deploy` starts runs on your machine unfenced: you asked to try the software, with your toolchains, in your browser. It runs from `dist/<module>`, a copy of the last commit outside `plain_modules`, so no regenerating agent reaches it. Nothing is installed on the machine for it: its dependencies go into the project, and a toolchain or system setting it lacks is yours to install - the release agent's shell refuses it, and tells you the command. See [deploy](deploy.md).
103
104
 
104
105
  ## What turri keeps beside the code
105
106
 
package/docs/sentinel.md CHANGED
@@ -35,10 +35,12 @@ Each pulse it checks from scratch, in a conversation of its own: its prompt, you
35
35
 
36
36
  1. **checks the pulse** - from what it is told, and when that is not enough, from the pulse's log, the ledger (`ledger`, `pulses`), `diagnose`, the code and the \*\*\*plain;
37
37
  2. **tests the release**, with `release-after-pulse` on: what was released is running where it is told, and it tries it - in the terminal with its shell (`curl`, the program itself, the logs), in a host also with what the host gives it, a browser say. How far it tests is its own judgement, from what the pulse changed and what the \*\*\*plain says it now does. With `release-after-pulse` off nothing is running, and it checks the pulse alone;
38
- 3. **finds out why**, when something is wrong - the pulse failed or stopped, it did not pass, the release did not come up, the software does not do what its \*\*\*plain says - and puts it to you as a notice, each action a task your chat's agent can carry out once you accept it;
38
+ 3. **finds out why**, when something is wrong - the pulse failed or stopped, it did not pass, the release did not come up, the software does not do what its \*\*\*plain says. A testing script, or where the config says the scripts are, it fixes itself, resumes the module, and tells you what it changed (below). Anything else it puts to you as a notice, each action a task your chat's agent can carry out once you accept it - and what the machine lacks, the exact command for you to run;
39
39
  4. **notifies no one** when all is well;
40
40
  5. **concludes**, last, whether all is well or not: what it checked and what it found, in a line or two. The chat you are in shows it - `✓ sentinel · app · pulse 3 · checked, it holds` - and its agent tells you so in a line, and does nothing more; when something was wrong, that its notice says what.
41
41
 
42
+ A host can ask it to check too: functional specs the person picks in a module's release - its own, or those of any module its requires chain builds on (`depths:gene-fragments` in predators' release) - in turri-desktop, on the preview's list of a module's built ones. It tests those, on its own judgement, in the module's release - its own codebase's last commit, released first unless that is what runs - and reports as for a pulse: a notice when something is wrong, and its conclusion. It is refused with the sentinel off, and for a module that does not parse, a functional spec it does not have, or one not built; see [in a host](hosting.md#the-sentinel).
43
+
42
44
  It checks one pulse at a time. A pulse that finishes while it works waits its turn, and is checked once it is done - from scratch, as every pulse is. A pulse that went well is checked until a newer pulse of its module finishes: its check is stopped, and the newer one is checked instead, at once - and a newer pulse of a module takes the place of one of it that went well and waits. A pulse that went wrong is looked into to its end.
43
45
 
44
46
  A notice may be **ignorable**: the sentinel marks one so when you may reasonably leave it as it is - chiefly a gap in the \*\*\*plain the build settled with an assumption: *the \*\*\*plain does not say what happens to passwords over 72 bytes; the build refuses them with 422*. Never something broken, a pulse that went wrong, a release that did not come up, nor the question whether to start the sentinel. Ignore one and it is left as the build has it, for good: nothing is done in your chat, and a line is written to the sentinel's guidance (`.turri/sentinel.md`, as `keep_guidance` writes) saying what was left as it is - its module, the gap, what the build does - and that you chose to. Every conversation after has it, and does not raise it again - unless the build no longer does what you accepted. To have it raised again, take the line out of `.turri/sentinel.md`.
@@ -47,7 +49,13 @@ Two functional specs that contradict each other stop a pulse in a way only you c
47
49
 
48
50
  ## What it may do
49
51
 
50
- Nothing that changes the project. Its file tools - `read`, `ls`, `grep`, `find` - read the whole project, its \*\*\*plain among them, and write nothing; its shell runs [behind the walls](sandbox.md) every agent's does - the command check, the OS sandbox where one is up, the audit - with the project read only and the network open, its home and temporary folder its own. It has `ledger`, `pulses`, `diagnose`, `parse`, `doctor` and the web, `notify_person` for its notices, `conclude` for when it is done with a pulse, `keep_guidance`, and what a host gives it. Whatever else it calls is refused: it never regenerates, steers, releases or changes \*\*\*plain, and never asks you a question - a notice is how it reaches you. What it found to do is yours to accept.
52
+ It fixes the project's tooling itself, and nothing else:
53
+
54
+ - **It fixes** the testing scripts - `test_scripts/`, a `run_*.sh` or `prepare_environment*.sh` at the project's root, each script `config.turri.yaml` names - and, in `config.turri*.yaml`, where the scripts are (`unittests-script`, `conformance-tests-script`, `prepare-environment-script`) and `toolchains:`. A script that runs `python3` where this machine has `python` of the version the \*\*\*plain names, a path that moved, a flag this machine's version of a tool does not take: it checks what it relies on in its shell (`command -v python`, `python --version`), edits the script, and calls `resume` - the module is brought up again, as when you ask for it, and the scripts run for real. Then it tells you, as a note in your chat (`kind: "fixed"`) with nothing to answer: what it changed and why, the lines before and after. Any other key of the config it changes is put back, and its edit refused.
55
+ - **It never changes \*\*\*plain.** The \*\*\*plain is your intent: what needs it changed is a notice, its action a task for your chat's agent once you accept it.
56
+ - **It installs nothing, and changes no setting of the machine's or your shell's** - not a toolchain, not a package, not a PATH line in your profile - under no circumstances: its shell refuses it, as every shell turri runs does. What the machine lacks is a notice with the exact command for you to run, and resuming as its action once you have.
57
+
58
+ Its file tools - `read`, `ls`, `grep`, `find` - read the whole project; `write` and `edit` reach the tooling above and nothing else, \*\*\*plain never. Its shell runs [behind the walls](sandbox.md) every agent's does - the command check, the OS sandbox where one is up, the audit - with the project read only and the network open, its home and temporary folder its own. It has `ledger`, `pulses`, `diagnose`, `parse`, `doctor` and the web, `resume`, `notify_person` for its notices, `conclude` for when it is done with a pulse, `keep_guidance`, and what a host gives it. Whatever else it calls is refused: it never steers, releases, or regenerates but by `resume` after a fix of its own, and never asks you a question - a notice is how it reaches you.
51
59
 
52
60
  ## Talking to it
53
61
 
@@ -69,4 +77,4 @@ A host sees the sentinel as one of its chats - `role: "sentinel"` in `chats()` a
69
77
 
70
78
  ## In the ledger
71
79
 
72
- `chat.opened` carries `role: "sentinel"` for its chat; `sentinel.checking` each pulse it starts a conversation for - `replaced`, the pulse of the same module whose check it stopped; `notice.put` and `notice.over` record each notice - the question before it opens among them - - its severity and module, and how it ended: `accepted`, `steered`, `dismissed`, `ignored`, `superseded` - and `sentinel.concluded` each pulse it is done with, `holds` or `wrong`.
80
+ `chat.opened` carries `role: "sentinel"` for its chat; `sentinel.asked` each check a host asks of it, its `check` and `module`; `sentinel.checking` each pulse - or check, with `check` - it starts a conversation for - `replaced`, the pulse of the same module whose check it stopped; `notice.put` and `notice.over` record each notice - the question before it opens among them - - its severity and module, and how it ended: `accepted`, `steered`, `dismissed`, `ignored`, `superseded` - and `sentinel.concluded` each pulse or check it is done with, `holds` or `wrong` - `unchecked`, a check that never ran.
package/docs/using.md CHANGED
@@ -136,8 +136,6 @@ It works mid-interview as well: the skill's agent has the same tool. Pulses alre
136
136
 
137
137
  Names are resolved strictly, because [pi](https://pi.dev)'s own matching guesses and says nothing ("gpt-5" can land on a Bedrock model you have no key for). An exact `provider/model-id` is taken as it is. A looser name is taken when it fits exactly one model you have credentials for, or is exactly one model's id in other words ("gpt 5.5" is `openai/gpt-5.5`, not `gpt-5.5-pro`). Anything else comes back as a short list and the agent asks you which one; a model whose provider has no credentials is never picked.
138
138
 
139
- A provider a [pi](https://pi.dev) extension registers - your company's own LLM gateway, say - works for every agent the conversation starts, not only for the conversation. Those agents load no extensions (they would load a second copy of turri), so each is given the providers the conversation's extensions registered, as they are when it starts. An unattended run - `turri regenerate`, `render` and the rest, outside the chat - has no conversation to take them from: there, only the providers in [pi](https://pi.dev)'s own configuration (`~/.pi/agent/models.json` and `auth.json`) are there, so a gateway those runs use has to be set up in `models.json`.
140
-
141
139
  To change [pi](https://pi.dev)'s own default, in `~/.pi/agent/settings.json`:
142
140
 
143
141
  ```json
@@ -146,6 +144,10 @@ To change [pi](https://pi.dev)'s own default, in `~/.pi/agent/settings.json`:
146
144
 
147
145
  A provider failure - no credits, bad key, rate limit - is raised with the provider's own message, rather than surfacing as an agent that said nothing. One that passes - overloaded, rate limited, unreachable, timed out - is waited out first, after [pi](https://pi.dev)'s own retries: six more tries, the wait doubled each time from 15 seconds up to five minutes (15s, 30s, 1m, 2m, 4m, 5m, a tenth either way so parallel jobs do not all come back at once), the agent carrying on where it was. Each wait - [pi](https://pi.dev)'s own retries too - is shown as it happens - a notification in the chat and the job panel's status, an orange line in a headless run - and listed in the run report's `turn_incidents`. So is a provider stalling: a request to the model that nothing has come back on for two minutes (`TURRI_PROVIDER_STALL`, in seconds; 0 never), said once for each silence while the turn goes on waiting. A turn turri stops itself - its time up, the agent going round in a circle - is the work's normal course and is not said, only listed.
148
146
 
147
+ ### Models from a pi extension
148
+
149
+ A provider a [pi](https://pi.dev) extension registers - a Claude subscription through Claude Code ([pi-claude-code](https://github.com/earendil-works/pi-claude-code), `claude-code/...`, see [a Claude subscription](claude-subscription.md)), your company's own LLM gateway - works everywhere turri needs a model. Install the extension as pi installs any (`pi install <source>`), and name its models in `config.turri.yaml` as any. In the chat, pi loads it, and every agent the conversation starts is given the providers the conversation's extensions registered, as they are when it starts - the agents themselves load no extensions, which would load a second copy of turri. A run with no conversation - `turri regenerate`, `turri change-plain`, `turri release` and the rest - loads the installed extensions itself, once, as pi loads them, and keeps only the providers they register; so do `turri doctor` and `turri init-config`, which check a model against them. An older turri that installed itself into every pi is among them, and is loaded as nothing.
150
+
149
151
  ## Module history
150
152
 
151
153
  Each `plain_modules/<module>` is a git repository whose git directory is `.plaingit` rather than `.git`, so it stays plain files to your own repository. A commit is made after every step that changes the module - a regeneration, a functionality regenerated, a conformance run, a regression repair, a \*\*\*plain change. `/lineage [module]` and `lineage` show it.
@@ -59,7 +59,7 @@ The other rules say what a spec means. This one says what turri does with a chan
59
59
  - In order of cost: change the spec where it is wrong or silent; regenerate the functional specs whose code went bad again, by name; regenerate the module from scratch, or its whole chain - only when the person asks for it or agrees to it
60
60
  - Pulses regenerate in the background: the spec can be changed while they run, and need not wait for them. A change inside what a running pulse regenerates steers it; the rest is planned again around it
61
61
  - A pulse that does not land is rolled back whole - code, tests and record together - and its module waits until the spec changes or the module is asked for again. Running it again unchanged usually ends the same way: look at why it did not land first
62
- - A finished pulse goes to the sentinel, a chat of turri's own - unless `sentinel: false`; under `sentinel: ask`, the default, only once the person said to start it, asked by turri before it first opens in a session (declined, a pulse goes to the chat that asked for it, as with `false`): it checks the pulse, tests what was released, and puts what is wrong to the person as a notice with what can be done. A pulse that landed is told to the chat the person is in too, only to say it landed and what the sentinel does with it, and when the sentinel is done with a pulse, what it found - the chat does nothing else about either; a pulse that went wrong is not told to it - the chat's agent is given a notice's task once the person accepts it, and does that
62
+ - A finished pulse goes to the sentinel, a chat of turri's own - unless `sentinel: false`; under `sentinel: ask`, the default, only once the person said to start it, asked by turri before it first opens in a session (declined, a pulse goes to the chat that asked for it, as with `false`): it checks the pulse, tests what was released, fixes a testing script - or where the config says the scripts are - itself and regenerates the module again, and puts anything else that is wrong to the person as a notice with what can be done. It never changes ***plain. turri installs nothing on the machine and changes none of its settings - not the sentinel, the chat, a release or any agent: a toolchain the machine lacks is the person's to install, told the exact command. A pulse that landed is told to the chat the person is in too, only to say it landed and what the sentinel does with it, and when the sentinel is done with a pulse, what it found - the chat does nothing else about either; a pulse that went wrong is not told to it - the chat's agent is given a notice's task once the person accepts it, and does that
63
63
 
64
64
  ## Where the cost is
65
65
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turri-dev/cli",
3
- "version": "0.1.28-next.d5f2680",
3
+ "version": "0.2.1-next.bc56a0d",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {