gentle-pi 4.3.0 → 4.5.0
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 +10 -7
- package/assets/agents/gentle-ai-worker.md +1 -1
- package/assets/design-canvas/canvas.css +648 -0
- package/assets/design-canvas/canvas.js +1497 -0
- package/assets/design-canvas/index.html +88 -0
- package/assets/design-canvas/inspector.js +290 -0
- package/assets/orchestrator-delegation-reference.md +2 -2
- package/assets/orchestrator-verification.md +1 -1
- package/assets/orchestrator.md +2 -2
- package/bin/engram-guard +1 -1
- package/bin/gentle-shell.mjs +138 -155
- package/docs/bundled-install.md +47 -42
- package/docs/delegated-verification.md +6 -0
- package/docs/gentle-agents-activity.md +5 -1
- package/docs/gentle-music.md +82 -0
- package/docs/gentle-shell.md +80 -10
- package/docs/install-wizard.md +30 -6
- package/docs/permission-modes.md +7 -2
- package/docs/readme-reference.md +72 -55
- package/docs/session-profile-format.md +26 -0
- package/docs/voice.md +259 -0
- package/docs/yolo-mode.md +17 -2
- package/extensions/ask-user-choice.ts +4 -1
- package/extensions/gentle-agents.ts +187 -40
- package/extensions/gentle-ai.ts +1765 -1185
- package/extensions/gentle-design.ts +158 -0
- package/extensions/gentle-music.ts +354 -0
- package/extensions/gentle-shell.ts +418 -79
- package/extensions/gentle-voice.ts +11 -0
- package/extensions/session-scratch.ts +41 -22
- package/extensions/skill-registry.ts +63 -8
- package/lib/agent-profiles.ts +26 -0
- package/lib/agents-config.ts +35 -0
- package/lib/agents-protocol.ts +57 -1
- package/lib/agents-runner.ts +52 -3
- package/lib/agents-session-transport.ts +101 -6
- package/lib/agents-widget.ts +14 -1
- package/lib/auto-permission-memory.ts +48 -18
- package/lib/auto-permission-runtime.ts +21 -6
- package/lib/clipboard-image.ts +147 -0
- package/lib/command-palette-catalog.ts +3 -2
- package/lib/commit-slice-signal.ts +1 -1
- package/lib/context-backstop.ts +36 -0
- package/lib/design-canvas-server.ts +947 -0
- package/lib/design-comments.ts +437 -0
- package/lib/design-handoffs.ts +313 -0
- package/lib/design-open-browser.ts +58 -0
- package/lib/design-sources.ts +120 -0
- package/lib/external-editor.ts +31 -0
- package/lib/gentle-design.ts +513 -0
- package/lib/gentle-shell-bundled.ts +141 -57
- package/lib/gentle-shell-launcher.ts +11 -4
- package/lib/gentle-shell-startup-update.ts +61 -9
- package/lib/gentle-shell-uninstall.ts +33 -1
- package/lib/image-attachments.ts +150 -0
- package/lib/inprocess-reviewer.ts +33 -2
- package/lib/jobs-sidebar-state.ts +22 -3
- package/lib/jobs-widget.ts +112 -0
- package/lib/nan-provider.ts +3 -0
- package/lib/native-review-cli.ts +11 -4
- package/lib/notification-audio-native.ts +149 -13
- package/lib/notification-audio.ts +4 -0
- package/lib/notification-pulse-worker.ts +82 -18
- package/lib/notification-service.ts +5 -1
- package/lib/orchestrator-presence.ts +78 -8
- package/lib/orchestrator-scope.ts +10 -0
- package/lib/orchestrator-state.ts +11 -3
- package/lib/permission-mode-policy.ts +2 -2
- package/lib/review-host-relay.ts +11 -2
- package/lib/review-reminder-receipt.ts +24 -1
- package/lib/session-profile-append-controller.ts +713 -0
- package/lib/session-profile-disk-reader.ts +182 -0
- package/lib/session-profile-freeze.ts +2 -2
- package/lib/session-profile-persistence.ts +15 -7
- package/lib/session-scratch.ts +52 -3
- package/lib/session-worktree-registry.ts +7 -0
- package/lib/shell-bar.ts +6 -7
- package/lib/shell-changes.ts +81 -5
- package/lib/shell-prompt.ts +4 -4
- package/lib/shell-sidebar-layout.ts +27 -7
- package/lib/shell-todo.ts +1 -1
- package/lib/verifier-admission.ts +5 -4
- package/lib/vim-editor-adapter.ts +14 -10
- package/lib/voice-artifacts.ts +188 -0
- package/lib/voice-command.ts +576 -0
- package/lib/voice-install.ts +455 -0
- package/lib/voice-platform.ts +99 -0
- package/lib/voice-push-to-talk.ts +262 -0
- package/lib/voice-session.ts +460 -0
- package/lib/voice-settings.ts +50 -0
- package/lib/voice-ui.ts +158 -0
- package/lib/yolo-session-policy.ts +58 -22
- package/package.json +1 -1
- package/runtime/gentle-shell-bundled.mjs +140 -56
- package/runtime/gentle-shell-launcher.mjs +11 -4
- package/runtime/gentle-shell-startup-update.mjs +61 -9
- package/runtime/gentle-shell-uninstall.mjs +33 -1
- package/runtime/native-review-cli.mjs +11 -4
- package/scripts/bundled-engram-migration.mjs +0 -6
- package/scripts/bundled-install.mjs +209 -13
- package/scripts/gentle-ai-installer.mjs +10 -10
- package/scripts/installer-downloads.mjs +31 -7
- package/scripts/installer-preflight.mjs +6 -4
- package/scripts/installer-windows.mjs +37 -7
- package/scripts/main-channel.mjs +91 -17
- package/scripts/pi-update.mjs +37 -7
- package/scripts/verify-package-files.mjs +26 -2
- package/scripts/voice-worker.cjs +476 -0
- package/skills/design/SKILL.md +110 -0
- package/tests/agent-profiles.test.ts +24 -0
- package/tests/agents-config.test.ts +61 -0
- package/tests/agents-fake-child.ts +8 -1
- package/tests/agents-protocol.test.ts +32 -0
- package/tests/agents-runner.test.ts +226 -5
- package/tests/agents-session-transport.test.ts +53 -3
- package/tests/ask-user-choice.test.ts +30 -0
- package/tests/auto-mode.test.ts +17 -0
- package/tests/auto-permission-memory-diagnostics.test.ts +56 -0
- package/tests/auto-permission-runtime.test.ts +85 -1
- package/tests/autonomous-guard.test.ts +20 -0
- package/tests/bundled-install.test.ts +276 -5
- package/tests/clipboard-image.test.ts +114 -0
- package/tests/command-palette.test.ts +4 -4
- package/tests/context-backstop.test.ts +70 -4
- package/tests/delegate-for-reason-contract.test.ts +2 -1
- package/tests/design-canvas-assets.test.ts +710 -0
- package/tests/design-canvas-server.test.ts +1096 -0
- package/tests/design-comments.test.ts +201 -0
- package/tests/design-handoffs.test.ts +282 -0
- package/tests/design-open-browser.test.ts +70 -0
- package/tests/design-sources.test.ts +132 -0
- package/tests/engram-safety.test.ts +132 -57
- package/tests/external-editor.test.ts +84 -0
- package/tests/fixtures/primary-session-prompt/gentleman.golden.md +3 -3
- package/tests/gentle-agents.test.ts +369 -24
- package/tests/gentle-ai-binary.test.ts +1 -1
- package/tests/gentle-ai-installer.test.ts +51 -51
- package/tests/gentle-ai.test.ts +928 -448
- package/tests/gentle-design.test.ts +1313 -0
- package/tests/gentle-music.test.ts +452 -0
- package/tests/gentle-shell-bundled.test.ts +321 -248
- package/tests/gentle-shell-launcher.test.ts +29 -2
- package/tests/gentle-shell-startup-update.test.ts +77 -1
- package/tests/gentle-shell-uninstall.test.ts +59 -0
- package/tests/gentle-shell.test.ts +227 -27
- package/tests/gentle-todo.test.ts +11 -0
- package/tests/image-attachments.test.ts +119 -0
- package/tests/image-paste-chips.test.ts +236 -0
- package/tests/inprocess-reviewer.test.ts +55 -2
- package/tests/installer-bundles.test.ts +12 -6
- package/tests/installer-downloads.test.ts +32 -0
- package/tests/installer-posix-bootstrap.test.ts +8 -8
- package/tests/installer-preflight.test.ts +16 -0
- package/tests/installer-server.test.ts +2 -2
- package/tests/installer-windows-bootstrap.test.ts +61 -3
- package/tests/installer-windows-diagnostics.test.ts +111 -0
- package/tests/jobs-widget.test.ts +138 -0
- package/tests/main-channel-upgrade.test.ts +232 -2
- package/tests/main-channel.test.ts +140 -21
- package/tests/model-profiles-preservation.test.ts +2 -2
- package/tests/nan-provider.test.ts +36 -0
- package/tests/native-review-capability-contract.test.ts +11 -4
- package/tests/native-review-parity.test.ts +1 -1
- package/tests/notification-audio-native.test.ts +128 -9
- package/tests/notification-customize.test.ts +17 -5
- package/tests/odd-routing-canonical-ratchet.test.ts +2 -1
- package/tests/orchestrator-budget.test.ts +5 -2
- package/tests/orchestrator-presence.test.ts +100 -2
- package/tests/orchestrator-rdd-ownership.test.ts +2 -2
- package/tests/orchestrator-scope.test.ts +14 -0
- package/tests/orchestrator-state.test.ts +29 -0
- package/tests/package-files.test.ts +34 -0
- package/tests/package-manifest.test.ts +6 -6
- package/tests/permission-mode-policy.test.ts +10 -1
- package/tests/pi-update.test.ts +104 -4
- package/tests/rdd-aware-verification-contract.test.ts +1 -1
- package/tests/review-host-relay-routing.test.ts +88 -1
- package/tests/review-host-relay.test.ts +9 -2
- package/tests/review-json-arguments.test.ts +20 -3
- package/tests/review-loadout-rdd-off-sdk.test.ts +23 -2
- package/tests/review-relay-transport-agent.test.ts +26 -0
- package/tests/review-reminder-receipt.test.ts +31 -1
- package/tests/runtime-harness.mjs +188 -211
- package/tests/session-changes.test.ts +2 -1
- package/tests/session-profile-append-controller-fork.test.ts +458 -0
- package/tests/session-profile-append-controller-pi.test.ts +290 -0
- package/tests/session-profile-append-controller.test.ts +731 -0
- package/tests/session-profile-disk-reader-pi.test.ts +183 -0
- package/tests/session-profile-disk-reader.test.ts +311 -0
- package/tests/session-profile-freeze.test.ts +6 -4
- package/tests/session-scratch.test.ts +68 -2
- package/tests/session-worktree-registry.test.ts +13 -1
- package/tests/shell-bar.test.ts +18 -6
- package/tests/shell-changes.test.ts +148 -1
- package/tests/shell-prompt.test.ts +3 -3
- package/tests/shell-render-cache.test.ts +134 -1
- package/tests/shell-sidebar-layout.test.ts +67 -0
- package/tests/short-check-routing-contract.test.ts +1 -1
- package/tests/skill-collision-prefixes.test.ts +3 -1
- package/tests/skill-registry-watcher.test.ts +17 -5
- package/tests/skill-registry.test.ts +47 -3
- package/tests/task-size-routing-contract.test.ts +1 -1
- package/tests/test-strength-contract.test.ts +1 -1
- package/tests/verifier-admission.test.ts +18 -1
- package/tests/vim-editor-adapter.test.ts +2 -2
- package/tests/voice-command.test.ts +773 -0
- package/tests/voice-install.test.ts +323 -0
- package/tests/voice-platform.test.ts +176 -0
- package/tests/voice-push-to-talk.test.ts +444 -0
- package/tests/voice-session.test.ts +434 -0
- package/tests/voice-settings.test.ts +49 -0
- package/tests/voice-ui.test.ts +97 -0
- package/tests/voice-worker.test.ts +445 -0
- package/tests/weak-model-economy-prompt.test.ts +32 -0
- package/tests/windows-hidden-processes.test.ts +25 -2
- package/tests/yolo-customize.test.ts +5 -1
- package/tests/yolo-mode.test.ts +1 -1
- package/tests/yolo-session-policy-capture.test.ts +104 -0
package/docs/install-wizard.md
CHANGED
|
@@ -59,7 +59,7 @@ it lets the window close.
|
|
|
59
59
|
Current requirements come from `package.json` and
|
|
60
60
|
[`gentle-ai-installer.mjs`](../scripts/gentle-ai-installer.mjs): Node ≥22.19.0,
|
|
61
61
|
Pi ≥1.2.0, pnpm acquisition 11.1.1, Gentle Shell package 4.0.0 and package-local
|
|
62
|
-
Gentle AI 4.
|
|
62
|
+
Gentle AI 4.3.1. Windows native source builds require Go ≥1.25.10 when the
|
|
63
63
|
required usable native binary is missing. A reusable binary does not require Go.
|
|
64
64
|
When a build needs Go and the user's Go is missing, older or unchecked, the installer uses
|
|
65
65
|
its own [pinned Go](#pinned-go) instead of blocking.
|
|
@@ -787,9 +787,13 @@ publishes main builds, so main is built on this computer
|
|
|
787
787
|
Gentleman-Programming/gentle-ai (GitHub API, raw SHA), runs
|
|
788
788
|
`go install github.com/gentleman-programming/gentle-ai/v4/cmd/gentle-ai@<sha>`
|
|
789
789
|
in a sealed Go environment (`GOPROXY=https://proxy.golang.org`,
|
|
790
|
-
`GOSUMDB=sum.golang.org`, `GOTOOLCHAIN=local`, `GOFLAGS=-modcacherw`),
|
|
791
|
-
|
|
792
|
-
|
|
790
|
+
`GOSUMDB=sum.golang.org`, `GOTOOLCHAIN=local`, `GOFLAGS=-modcacherw`),
|
|
791
|
+
asks Go (`go list -m -json`, same environment) which module version that
|
|
792
|
+
commit is (a release tag such as `v4.2.0`, or a pseudo-version) and requires
|
|
793
|
+
its origin to be that exact commit, requires the binary to embed that module
|
|
794
|
+
version (`go version -m`) and to report it, all in the `.build` work
|
|
795
|
+
folder, and only then moves it to `<config home>/main/gentle-ai/<sha>/`
|
|
796
|
+
(a failed rebuild leaves an already registered build in place) and registers it as the
|
|
793
797
|
`gentle-pi.dev-binary/v1` override, which never falls back to the pinned
|
|
794
798
|
binary silently.
|
|
795
799
|
2. `install-shell-main`: downloads the latest `main` commit's source tarball,
|
|
@@ -812,8 +816,28 @@ publishes main builds, so main is built on this computer
|
|
|
812
816
|
a version it cannot check) it builds with the pinned Go under
|
|
813
817
|
`<config home>/tools/go`, downloading and verifying it there with the same
|
|
814
818
|
`acquireGo` as the wizard when no earlier run published it, and only when
|
|
815
|
-
Gentle AI is rebuilt. A failed download stops with
|
|
816
|
-
before
|
|
819
|
+
Gentle AI is rebuilt. A failed download stops the Gentle AI build with
|
|
820
|
+
`main-requires-tools` before it starts (a main Shell that moved is still
|
|
821
|
+
installed, as below); the user's Go is never run for the build.
|
|
822
|
+
- When the Gentle AI step of `gentle-shell upgrade --channel main` fails (the
|
|
823
|
+
build, its verification, or getting the pinned Go) and the main Shell moved,
|
|
824
|
+
the upgrade still packs and installs that Shell, records no channel, prints
|
|
825
|
+
`Updated Gentle Shell to the latest main (<sha12>); Gentle AI was not updated.`
|
|
826
|
+
and exits 1 with the original error (code and message) followed by
|
|
827
|
+
`; Gentle Shell was updated to main <sha12> but Gentle AI was not: run
|
|
828
|
+
gentle-shell upgrade --channel main to finish`. The retry then rebuilds Gentle
|
|
829
|
+
AI with the new Shell's code, so a fix in the main-channel upgrade path reaches
|
|
830
|
+
an install whose own copy of it is broken; a cause the new Shell does not fix
|
|
831
|
+
(a Go download that keeps failing, for example) still has to be resolved first. Until then Gentle AI stays the
|
|
832
|
+
previously registered main build or the pinned binary: a rejected build is
|
|
833
|
+
never registered. When the Shell install fails as well, its error is reported
|
|
834
|
+
with `; Gentle AI was not updated either (<Gentle AI error>)`. An unexpected
|
|
835
|
+
error that has no main-channel code (a filesystem `EACCES`, for example) is
|
|
836
|
+
reported as `main-upgrade-incomplete` with its own message and the same
|
|
837
|
+
suffix, so neither the retry advice nor either error is lost. When the Shell
|
|
838
|
+
is already current, a failed Gentle AI step fails as before, with nothing
|
|
839
|
+
installed or recorded. The wizard's runner is the one bundled with the
|
|
840
|
+
downloaded installer and does not get this behavior from a newer main.
|
|
817
841
|
- Trust: Gentle AI source is verified by Go's checksum database; the Gentle Shell
|
|
818
842
|
source is fetched over TLS from GitHub by exact commit SHA, with no pinned
|
|
819
843
|
digest. Main builds are development builds.
|
package/docs/permission-modes.md
CHANGED
|
@@ -53,14 +53,15 @@ Changing the default does **not** change the current session. To return this ses
|
|
|
53
53
|
| **Normal** | Existing permission behavior; the default when no valid global preference exists. |
|
|
54
54
|
| **Auto** | A separate reviewer using the current session model checks eligible actions against live user intent before execution. Local reads are classified too; locality does not exempt an action from explicit restrictions. |
|
|
55
55
|
| **YOLO** | Standing permission for ordinary already-authorized work and delivery; no Auto classifier. Destructive and independent consent boundaries remain, except recursive removal of the session's own [temp scratch](yolo-mode.md#temp-scratch-removal). [Full YOLO details](yolo-mode.md). |
|
|
56
|
+
| **Super Yolo** | No permission prompts at all, including data-loss confirmations and configured guardrail actions. The only remaining line is the sensitive-path guard: read/write/edit of `.env`, `.ssh`, keychains, `*.pem/*.key/*.p12/*.pfx`, `secrets/` and cloud credential files stays hard-blocked. Code-level catastrophic denies (`rm -rf /`, `--no-preserve-root`, `git reset --hard`, forced clean, force push) also remain. |
|
|
56
57
|
|
|
57
58
|
## Commands and menu
|
|
58
59
|
|
|
59
60
|
| Command | Effect |
|
|
60
61
|
| --- | --- |
|
|
61
|
-
| `/gentle:mode normal`, `auto`, or `yolo` | Select exactly one mode for the current interactive primary session. |
|
|
62
|
+
| `/gentle:mode normal`, `auto`, `yolo`, or `super-yolo` | Select exactly one mode for the current interactive primary session. |
|
|
62
63
|
| `/gentle:mode status` or `/gentle:mode` | Show current mode and saved default. |
|
|
63
|
-
| `/gentle:mode default normal`, `auto`, or `yolo` | Save the default for new primary sessions, leaving the current mode unchanged. |
|
|
64
|
+
| `/gentle:mode default normal`, `auto`, `yolo`, or `super-yolo` | Save the default for new primary sessions, leaving the current mode unchanged. |
|
|
64
65
|
| `/gentle:yolo enable`, `disable`, or `status` | Existing shortcut; enable selects YOLO, disable selects Normal. |
|
|
65
66
|
|
|
66
67
|
In `/gentle:customize` → **Editor**, use **Session permissions** to change the current mode, or **Default permissions** to save a future-session preference. The original **YOLO: ON/OFF · session only** row still toggles the live mode; it does not save a default. Browsing, previews, and closing the menu do not grant permission.
|
|
@@ -116,6 +117,10 @@ The **Auto checks** status and `gentle-auto-permission` session entries account
|
|
|
116
117
|
|
|
117
118
|
The dedicated `permission-mode.json` in Gentle Pi's resolved user config home contains a strict versioned preference. Saving uses a private atomic replacement; malformed or unreadable existing preferences fall back to Normal and refuse an overwrite until repaired. Use the human command/menu path rather than asking model tools to edit this authority file.
|
|
118
119
|
|
|
120
|
+
Model `write`/`edit` calls keep the config home protected except for the main-channel updater's `dev-binary.json`, `channel.json`, `main/` and `tools/go`. Those destinations select or build executable code, so they still require authorization under the current mode's ordinary checks; Auto classifies them and can deny an update. They are not automatically allowed. Permission preferences, global and project `runtime-guardrails.json`, their parent directories and symlink aliases resolving to them stay blocked even if a classifier would allow the action. Other config-home state, including model routing, persona and privacy preferences, remains protected.
|
|
121
|
+
|
|
122
|
+
Shell recognition remains deliberately conservative: commands mentioning the config home or policy filenames can still be blocked. This change does not relax shell protection, authorize routing around a denial, or turn the hook into a sandbox.
|
|
123
|
+
|
|
119
124
|
Live mode selection is bound to the SessionManager, session ID and canonical Git clone identity, or the canonical workspace directory outside Git. Session replacement, shutdown and reload revoke live callbacks and pending actions. A newly initialized primary session may select its saved default; this is a new application of the global preference, not restoration of an old session grant. Disable the saved default as well if future sessions must stay Normal.
|
|
120
125
|
|
|
121
126
|
## Limits
|
package/docs/readme-reference.md
CHANGED
|
@@ -157,7 +157,7 @@ otherwise `herdr` from `PATH`, without a shell.
|
|
|
157
157
|
| **Skill creation workflow** | Provides the `gentle-ai-skill-creator`/`gentle-ai-skill-improver` skills, `/skill-creation` prompt, and packaged style guide for LLM-first skills. |
|
|
158
158
|
| **Delivery skills** | Includes issue-first PRs, chained PRs, work-unit commits, cognitive docs, comment writing, and Judgment Day review. |
|
|
159
159
|
| **Bounded native review** | Freezes one candidate, dispatches only controller-selected lenses, and records native authority. Review outcomes are informational; delivery follows ordinary repository policy. |
|
|
160
|
-
| **Verified native runtime** | The current source checkout provisions the exact package-local Gentle AI v4.
|
|
160
|
+
| **Verified native runtime** | The current source checkout provisions the exact package-local Gentle AI v4.3.1 runtime: signed, SHA-256-pinned release archives on Darwin/Linux and a Go SumDB-verified source build on Windows x64/arm64. It validates package-local integrity and rejects PATH, global, sibling, symlink, and mode fallbacks. |
|
|
161
161
|
| **Runtime safety** | Blocks destructive shell commands, asks for confirmation for sensitive operations, and blocks direct read/write/edit access to sensitive paths. Blocks writing a test file that reads git history at a literal commit or points `TMPDIR` inside the working directory (including a relative path such as `.tmp`, `./.tmp`, or `tmp/x`), in the primary session and in subagents. Refuses native review tools (`gentle_review*`) called from inside another tool, such as a codemode script: they run only as direct tool calls. |
|
|
162
162
|
|
|
163
163
|
## Audio notifications
|
|
@@ -218,11 +218,11 @@ This installs the current npm release; select an explicit version if you need a
|
|
|
218
218
|
|
|
219
219
|
### Source checkout
|
|
220
220
|
|
|
221
|
-
This checkout declares `gentle-pi` `4.0.0` with a package-local Gentle AI `v4.
|
|
221
|
+
This checkout declares `gentle-pi` `4.0.0` with a package-local Gentle AI `v4.3.1` pin. Checkout metadata alone is not proof of npm publication; verify the registry version and its release workflow.
|
|
222
222
|
|
|
223
223
|
### Pi compatibility
|
|
224
224
|
|
|
225
|
-
The current package requires Pi 1.2.0 or newer and Node >=22.19.0. Development tests resolve Pi through the open `>=1.0.0` development range. The private Vim editor adapter admits only the audited Pi `0.99.1`, `0.99.2`, `1.0.0`, `1.1.0`, and `1.
|
|
225
|
+
The current package requires Pi 1.2.0 or newer and Node >=22.19.0. Development tests resolve Pi through the open `>=1.0.0` development range. The private Vim editor adapter admits only the audited Pi `0.99.1`, `0.99.2`, `1.0.0`, `1.1.0`, `1.2.0`, `1.3.0`, and `1.4.0` releases; any other release keeps ordinary prompt editing until its editor is audited. Use the latest Pi release; gentle-pi does not update your installed Pi automatically. Children, including any `GENTLE_PI_AGENTS_PI` override, must emit `agent_settled`: `agent_end` records a run's output but is not completion because retries or queued continuations may follow.
|
|
226
226
|
|
|
227
227
|
The [`v2.6.0` release](https://github.com/Gentleman-Programming/gentle-shell/releases/tag/v2.6.0) added persistent registered worktrees and grouped `/gentle:changes` views; fuller workspace interaction details are in the [Gentle Shell reference](gentle-shell.md). It also adds named atomic `/gentle:profiles`, native review intended-untracked selection and provider continuations, and opt-in custom ask responses. Pi recognizes its global Git-managed package path; subsystems install with explicit recovery guidance when npm lifecycle work was skipped. Windows keeps child consoles hidden and fixes ownership mode; Gentle Todo keeps the next pending task visible when collapsed.
|
|
228
228
|
|
|
@@ -234,7 +234,7 @@ Project-local installs (`pi install -l`), Git installs outside that exact global
|
|
|
234
234
|
|
|
235
235
|
Malformed/nonobject JSON, symlink/nonregular settings, unsafe paths, or a busy settings lock fail without replacing settings. The installer coordinates with Pi's cooperative settings lock and uses atomic replacement; it does not guarantee safety against noncooperating writers or malicious concurrent directory replacement. Already-fullscreen settings remain byte-identical. Native installation failure leaves settings untouched; `GENTLE_PI_SKIP_GENTLE_AI_INSTALL=1` skips only native provisioning, not the recognized global fullscreen setting.
|
|
236
236
|
|
|
237
|
-
### RDD history and
|
|
237
|
+
### RDD history and default
|
|
238
238
|
|
|
239
239
|
Native RDD was introduced in `gentle-pi` `v0.15.0` on 2026-07-10 with bounded review transactions. The current stable release, [`v3.5.1`](https://github.com/Gentleman-Programming/gentle-shell/releases/tag/v3.5.1), includes native RDD:
|
|
240
240
|
|
|
@@ -243,9 +243,9 @@ Native RDD was introduced in `gentle-pi` `v0.15.0` on 2026-07-10 with bounded re
|
|
|
243
243
|
pi install npm:gentle-pi@3.5.1
|
|
244
244
|
```
|
|
245
245
|
|
|
246
|
-
RDD
|
|
246
|
+
RDD is optional and on by default (since Gentle AI v4.0.0). Turn it off anytime with `/gentle:review-mode disable` for this clone or `gentle-ai review mode disable` machine-wide; `/gentle:review-mode enable` only clears a clone-local off, and `status` lets you inspect the mode without changing it. The `.git/gentle-ai/candidate-views` parent must sit on a filesystem that honors private POSIX modes (or equivalent Windows ACLs); WSL DrvFS mounts without metadata can reject START before lineage creation.
|
|
247
247
|
|
|
248
|
-
The source checkout's RDD integration installs Gentle AI only into its private `.gentle-ai/` directory. Darwin and Linux use pinned release assets with asset and executable SHA-256 verification (signed archives for source pin `v4.
|
|
248
|
+
The source checkout's RDD integration installs Gentle AI only into its private `.gentle-ai/` directory. Darwin and Linux use pinned release assets with asset and executable SHA-256 verification (signed archives for source pin `v4.3.1`; raw prerelease binaries only under a prerelease pin). Windows x64 and arm64 build the exact `v4.3.1` source tag with a local Go 1.25.10+ toolchain, a sealed Go environment, `GOTOOLCHAIN=local`, and `GOSUMDB=sum.golang.org`; it does not download Go automatically (the [installation wizard](install-wizard.md#pinned-go) can put its own pinned Go first on PATH for that build). Go runs in a short private directory under the system temp directory, never inside the package, because a deep pnpm store path pushes Go's working directories past MAX_PATH; a failed build prints its whole cause chain with the failing command's output tail. Windows provenance is Go-toolchain plus SumDB evidence and postinstall tamper detection, **not** Authenticode or protection against a malicious joint binary-and-manifest replacement. Package-private locks coordinate cooperative concurrent or crashed installers; their tombstones fail closed. A malicious same-user process with write access to package-private `node_modules` is outside that protocol because it can already replace package code, binary, or manifest, and portable Node has no pathname-delete CAS. It never uses `PATH` or a global `gentle-ai` installation. For development or offline installs only, set `GENTLE_PI_SKIP_GENTLE_AI_INSTALL=1`; native review operations then fail closed with an actionable `package-local-binary-missing` error. To recover explicitly, if `GENTLE_PI_SKIP_GENTLE_AI_INSTALL` is set, remove or unset it before changing to the installed `gentle-pi` package directory. Then run `node scripts/install-gentle-ai.mjs`. This invokes the package-owned installer without relying on a global binary or npm configuration change. A missing binary can result from skipped lifecycle scripts, but does not prove that lifecycle scripts were disabled.
|
|
249
249
|
|
|
250
250
|
Recommended companion packages, into the standalone `gentle-shell` home:
|
|
251
251
|
|
|
@@ -304,6 +304,7 @@ gentle-shell home [link|isolated|<path>]
|
|
|
304
304
|
gentle-shell [home selectors] setup [--dry-run]
|
|
305
305
|
gentle-shell upgrade [--channel release|main]
|
|
306
306
|
gentle-shell upgrade --rollback
|
|
307
|
+
gentle-shell update [pi|self|--self|--all] --latest
|
|
307
308
|
gentle-shell self-uninstall [--dry-run] [--yes] [--include-shared]
|
|
308
309
|
```
|
|
309
310
|
|
|
@@ -378,17 +379,17 @@ Tradeoff: `--link` shares one credential store with pi; `import-pi` duplicates i
|
|
|
378
379
|
|
|
379
380
|
`gentle-shell list` and extension updates follow that same home selection. `gentle-shell update --extensions-only` preserves Pi's extension-only command; `--extensions`, package targets, and model updates also stay with Pi.
|
|
380
381
|
|
|
381
|
-
`gentle-shell update` updates the selected Pi through its verified npm or pnpm global owner, avoiding Pi's self-update refusal for pnpm v11 linked stores. Ownership requires successful global listing JSON, an exact canonical listed package-root/CLI match, and binding to the selected runtime. An adjacent peer (the launcher's `bundled` runtime) is supplied by the exact listed `gentle-pi` package: that Shell package is reinstalled at its current version so the manager re-resolves the peer, and a separate global Pi is never the target, because updating it leaves the peer a Shell install runs unchanged. A `PATH` or `GENTLE_SHELL_PI` runtime is supplied only by its own listed global Pi package; when that executable is a package-manager shim (pnpm's POSIX shim, a `.cmd`), Shell follows the single `dist/bundle/cli.js` it names, relative to the shim's directory, and refuses shims naming none or several. Pi and Shell are never installed together in a comma group, and unrelated packages are never reinstalled. Merely residing under `PNPM_HOME` proves nothing. Adjacent peers resolve where the package manager places them: nested under the Shell package (npm), beside it in pnpm's linked store, or in the global group's own `node_modules`. npm source/link entries are rejected. pnpm updates additionally require that the actual old global group contains only the target top-level package: aggregated listings may contain other, separate groups, but shared groups are rejected because pnpm can remove the whole old group. Unknown, malformed, failed, or ambiguous ownership refuses before installation; update source checkouts and other unsupported layouts with their supplying package manager.
|
|
382
|
+
`gentle-shell update` updates the selected Pi through its verified npm or pnpm global owner, avoiding Pi's self-update refusal for pnpm v11 linked stores. Ownership requires successful global listing JSON, an exact canonical listed package-root/CLI match, and binding to the selected runtime. An adjacent peer (the launcher's `bundled` runtime) is supplied by the exact listed `gentle-pi` package: that Shell package is reinstalled at its current version so the manager re-resolves the peer (a main-channel `<version>-main.<sha12>` Shell, which is never published, from the tarball `gentle-shell upgrade --channel main` packed under `<config home>/main/packages/` (an absolute `GENTLE_PI_CONFIG_HOME`, else `~/.pi/gentle-ai`; a relative override is refused), refusing without installation when it is missing and naming `gentle-shell upgrade --channel release` then `--channel main` as the rebuild path), and a separate global Pi is never the target, because updating it leaves the peer a Shell install runs unchanged. A `PATH` or `GENTLE_SHELL_PI` runtime is supplied only by its own listed global Pi package; when that executable is a package-manager shim (pnpm's POSIX shim, a `.cmd`), Shell follows the single `dist/bundle/cli.js` it names, relative to the shim's directory, and refuses shims naming none or several. Pi and Shell are never installed together in a comma group, and unrelated packages are never reinstalled. Merely residing under `PNPM_HOME` proves nothing. Adjacent peers resolve where the package manager places them: nested under the Shell package (npm), beside it in pnpm's linked store, or in the global group's own `node_modules`. npm source/link entries are rejected. pnpm updates additionally require that the actual old global group contains only the target top-level package: aggregated listings may contain other, separate groups, but shared groups are rejected because pnpm can remove the whole old group. Unknown, malformed, failed, or ambiguous ownership refuses before installation; update source checkouts and other unsupported layouts with their supplying package manager.
|
|
382
383
|
|
|
383
384
|
After a successful install, Shell reads the supplied Pi version back from a fresh global listing and reports it, naming the previous version when it changed. An unchanged pnpm result also names pnpm's `minimumReleaseAge` setting: pnpm installs only releases older than that age (pnpm 11 defaults to 4320 minutes), so a very recent Pi release is picked up once it is old enough; Shell reports the rule rather than overriding it. Both the listing and the install run from the system temporary directory, so a project's `packageManager` pin in the current directory never changes which pnpm answers. When the version cannot be read back, the output says so and points at `gentle-shell --version`.
|
|
384
385
|
|
|
385
|
-
Prefix-bundled installations keep their existing `gentle-shell upgrade` route for Pi. `update --all` updates the verified owner before forwarding extension updates; an ownership refusal stops without mutation. Shell's `upgrade` and `self-uninstall` ownership behavior is unchanged.
|
|
386
|
+
Prefix-bundled installations keep their existing `gentle-shell upgrade` route for Pi, or `gentle-shell update --latest` for the newest published Pi without the release's verified lockfile (see [`upgrade`](#upgrade-subcommand-and-channels)). Outside a bundled install `--latest` changes nothing: `update` already installs the latest Pi. `update --all` updates the verified owner before forwarding extension updates; an ownership refusal stops without mutation. Shell's `upgrade` and `self-uninstall` ownership behavior is unchanged.
|
|
386
387
|
|
|
387
388
|
### `setup` subcommand
|
|
388
389
|
|
|
389
|
-
**Bundled Engram safety:**
|
|
390
|
+
**Bundled Engram safety:** Shell shares the global Engram server on `127.0.0.1:7437`, like other agents' hooks. A running server is reused only through Engram's exact `GET /compatibility` ready contract; when nothing listens, Shell starts the checksum-pinned Engram 3.5.2 core as a detached `engram serve` (Engram's default port and `~/.engram`, no update check, no GitHub tokens) and waits up to 10 seconds for that same contract, so you never start the server yourself. An existing store does not disable memory by itself, whoever created it; only a database header from a newer Engram schema keeps Shell from starting its older core on it. Anything else (a server that does not verify, a token-protected or unknown server, a start that fails or never reports ready) disables memory for that launch with an explanation of the missing safety evidence and backup precautions (matching versions or updating alone do not prove compatibility); Shell never stops or replaces a listening server. Shell always points `ENGRAM_BIN` at its own guard (`bin/engram-guard`), which fails before any store access for every gentle-engram from 0.4.1 on, whichever Pi route loaded it, so memory reaches the store only through the verified server's `ENGRAM_URL`. No compatibility is inferred from versions. An explicit `ENGRAM_BIN` or `ENGRAM_URL` is never replaced and bypasses the guard. Every launch also pins `npm:gentle-engram@0.4.2` through Pi's own `install` command and verifies `engram.startupPolicy: 1`; a failed check is reported and Shell still starts. See [bundled startup safety](bundled-install.md#engram-startup-safety) for the full rules and known limits.
|
|
390
391
|
|
|
391
|
-
The memory decision never skips or fails bundled setup: it always publishes the verified core, runs Gentle AI and pins the companion, then only selects the Engram environment (
|
|
392
|
+
The memory decision never skips or fails bundled setup: it always publishes the verified core, runs Gentle AI and pins the companion, then only selects the Engram environment (the guard as `ENGRAM_BIN`, plus `ENGRAM_URL` when memory is allowed) for setup children and the launched Pi. `--dry-run` installs nothing. Non-bundled setup keeps the existing behavior described below.
|
|
392
393
|
|
|
393
394
|
`gentle-shell setup` provisions the resolved home — the same home selection as any other invocation, `--isolated` by default, or `--link`/`--home <path>` when given before `setup` — with the same companion packages a regular `gentle-ai install --agent pi` installs into a Pi agent home: `npm:gentle-pi`, `npm:gentle-engram`, `npm:@juicesharp/rpiv-ask-user-question`, `npm:pi-web-access`, `npm:pi-btw`, plus running `pi-engram init`. It never touches `~/.pi/agent` unless you pass `--link`.
|
|
394
395
|
|
|
@@ -438,7 +439,7 @@ If none resolve, `gentle-shell` exits 1 naming all three options. Once a runtime
|
|
|
438
439
|
| `GENTLE_SHELL_NO_AUTO_SETUP` | Set to `1` to skip automatic first-run provisioning (see "First run in an isolated or custom home" below). |
|
|
439
440
|
| `ENGRAM_STARTUP_POLICY` | Bundled startup recomputes `allow` or `disabled` from safety evidence. Explicit empty/invalid values remain disabled; user `allow` does not override unknown data. Standalone provider behavior with the variable absent is unchanged. |
|
|
440
441
|
| `ENGRAM_STARTUP_NOTICE` | Display-only recovery guidance; never executed. |
|
|
441
|
-
| `ENGRAM_BIN`, `ENGRAM_URL`, `ENGRAM_PORT`, `ENGRAM_DATA_DIR`, `ENGRAM_DATABASE_URL` | Explicit selections are not probed by Shell and keep bundled memory disabled. An explicit `ENGRAM_BIN` or `ENGRAM_URL` is never replaced and bypasses the guard (an `ENGRAM_URL` alone still gets the verified core, or the guard, as `ENGRAM_BIN`); without them, bundled Shell sets `ENGRAM_BIN`
|
|
442
|
+
| `ENGRAM_BIN`, `ENGRAM_URL`, `ENGRAM_PORT`, `ENGRAM_DATA_DIR`, `ENGRAM_DATABASE_URL`, `ENGRAM_SERVER_MODE` | Explicit selections are not probed by Shell and keep bundled memory disabled. An explicit `ENGRAM_BIN` or `ENGRAM_URL` is never replaced and bypasses the guard (an `ENGRAM_URL` alone still gets the verified core, or the guard, as `ENGRAM_BIN`); without them, bundled Shell sets `ENGRAM_BIN` to the guard and, for verified reuse, `ENGRAM_URL`. |
|
|
442
443
|
|
|
443
444
|
### Loading the package
|
|
444
445
|
|
|
@@ -555,6 +556,7 @@ every `update` form that updates Pi itself explains that and runs
|
|
|
555
556
|
`gentle-shell upgrade` (in a terminal) or names it. Those forms are no target,
|
|
556
557
|
`--self`, `self` or `pi`, `--all`, and `self` or `pi` with `--extensions`. The
|
|
557
558
|
extension part of an "all" form, and every package update, still reaches Pi.
|
|
559
|
+
`gentle-shell update --latest` (also with `pi`, `self`, `--self` or `--all`) installs the newest published stable Pi with the active Gentle Shell instead, without the release's verified lockfile: it first warns that Gentle Shell features relying on audited Pi internals (such as the Vim editor) may turn off until a Gentle Shell release verifies that Pi, then verifies and switches to it like `upgrade`, keeping the previous version for `gentle-shell upgrade --rollback`. Afterwards `gentle-shell upgrade` never downgrades that Pi: a release of the same Gentle Shell with an older verified Pi changes nothing, and a newer Gentle Shell release upgrades as usual. When the active Pi is already newer than the published `latest` (the dist-tag moved back), `--latest` changes nothing. Outside a bundled install, `gentle-shell update --latest` is the ordinary managed Pi update, which already installs the newest published Pi.
|
|
558
560
|
In a bundled install Pi and the agent's commands keep your own environment;
|
|
559
561
|
Pi installs packages with Gentle Shell's npm through the `npmCommand` setting
|
|
560
562
|
of its own home. Details: [Bundled install](bundled-install.md#launcher-in-a-bundled-install).
|
|
@@ -657,8 +659,7 @@ Synthetic tests prove the observer's behavior, not the cause of issue #213. A ne
|
|
|
657
659
|
```text
|
|
658
660
|
/gentle:status Check package assets and global model config.
|
|
659
661
|
/gentle:doctor Run read-only diagnostics for assets, config, tools, guards, and Herdr setup.
|
|
660
|
-
/gentle:models
|
|
661
|
-
/gentle:profiles Create, switch, and manage global agent-model profiles.
|
|
662
|
+
/gentle:profiles Open the models screen on this repository's profile. Subcommands: export <name>, import, publish <name>, export-routing, restore-routing.
|
|
662
663
|
/gentle:persona Switch between gentleman and neutral persona modes.
|
|
663
664
|
/gentle:background-subagents Show or set the managed background-subagents policy, with its deciding source.
|
|
664
665
|
/gentle:review-mode Show or set the receipt-driven development mode (status|enable|disable).
|
|
@@ -721,7 +722,7 @@ parent git/status + clarify → one worker writes authorized fixes → focused v
|
|
|
721
722
|
|
|
722
723
|
A second admission check stops small-task delegation: in the primary session, a `gentle-ai-worker` or `worker` launch is admitted only when its task or context has a line that starts with `Spec: odd/tasks/<feature>.md` and names a task `T<n>` later on that line (for example `, T2, S3` or the delegation card's `(read until "## Log"). Do T2; S3.`), where the document is a regular file under the writer root's `odd/tasks/` after resolving symlinks, or when the parent's measured context reaches the context backstop described below. Otherwise the launch is rejected with an instruction to write the unit inline. Judgment Day fix agents, read-only subagents, and continuations are not affected.
|
|
723
724
|
|
|
724
|
-
A third admission check keeps the independent verifier for high-risk changes: in the primary session, a `gentle-ai-verify` launch is admitted only when its task or context has a
|
|
725
|
+
A third admission check keeps the independent verifier for high-risk changes: in the primary session, a `gentle-ai-verify` launch is admitted only when its task or context has a declaration that starts a line (optionally as a list item) or a sentence (after `.`, `!` or `?` and a space) with `Risk:` and names a Task Size high-risk item first, in the form `Risk: item N` with N from 1 to 6 (several items are allowed, for example `Risk: item 2, item 3 (reason)`), or when it carries a feature-document task line the writer check above accepts, or when the parent's measured context reaches the context backstop. `Risk: none`, a mention inside a sentence, or no declaration is rejected with an instruction to run the change's focused test and suite inline, not to retry the launch, and never to add a Risk line or create a feature document only to get a verifier admitted. Subagent children, continuations, writers, Judgment Day agents, native review relays, and read-only explorers are not affected.
|
|
725
726
|
|
|
726
727
|
Every subagent child runs with its own `TMPDIR` (also `TMP` and `TEMP` on Windows): a fresh `gaXXXXXX` directory created under the inherited temp directory (joined to the inherited value as given, never its real path), so scratch the child makes with `mktemp` stays out of the worktree. The runtime removes that directory and everything in it when the child ends, including a failed launch. A quarantined child, whose process exit is unconfirmed, keeps its directory under the system temp directory, because a surviving descendant may still use it; once its exit is proven, including a process group that ends after the child's own exit, the directory is removed and the slot is freed. Each continuation is a new child with a new directory.
|
|
727
728
|
|
|
@@ -810,7 +811,7 @@ flowchart TD
|
|
|
810
811
|
|
|
811
812
|
VALIDATE is informational. Commit, push, PR, and release commands follow ordinary repository policy; RDD never authorizes, rewrites, consumes review state for, or blocks them. Dangerous-command safety and destructive-review consent remain independent.
|
|
812
813
|
|
|
813
|
-
For the source checkout, native contract pairing is exact: this adapter resolves only the integrity-verified package-local Gentle AI v4.
|
|
814
|
+
For the source checkout, native contract pairing is exact: this adapter resolves only the integrity-verified package-local Gentle AI v4.3.1 executable, independently hashes it, then negotiates `gentle-ai.review-integration/v2` outside the repository. Capabilities are cached by that executable digest. Every START, target status, FINALIZE, and validate request passes the same contract identifier. Negotiated envelopes decode exactly against the vendored schemas; `recover` routes only the provider-selected `action_disposition`, and optional additions require a future compatible schema/minor that the provider explicitly advertises and the consumer negotiates.
|
|
814
815
|
|
|
815
816
|
Contract `/v2` replaces the Base64 `candidate_diff` reviewer transport of `/v1` with immutable `base_tree`/`candidate_tree` plus an ordered `changed_path_manifest` and never an inline patch. `gentle-pi` negotiates `/v2` only, with no dual-lane fallback; the cutover landed as one atomic commit against gentle-ai v2.2.2 (tracked by the `migrate-review-integration-v2` change), and the `/v1` schemas stay packaged because the `/v2` schemas `$ref` into their fragments. This provider contract version is unrelated to Pi's own internal "compact-v2" review-authority naming used below — the shared digit is coincidental, not a version pairing.
|
|
816
817
|
|
|
@@ -820,7 +821,7 @@ Candidate views materialize tracked Git symlinks from their frozen blobs even wh
|
|
|
820
821
|
|
|
821
822
|
On POSIX, if START rejects a group- or world-accessible `.git/gentle-ai/candidate-views` parent, Pi reports `candidate-owner-parent-privacy` before native START. When a sanitized probe shows the filesystem cannot represent private POSIX modes (for example WSL DrvFS mounts without `metadata`), Pi instead reports `candidate-owner-parent-chmod-ineffective` with guidance to move the Git common directory to a POSIX-metadata filesystem or enable metadata support. Inspect that parent's ownership and permissions and correct them out of band before retrying; Pi does not change them automatically. Other owner-preparation failures retain a generic diagnostic rather than exposing filesystem errors.
|
|
822
823
|
|
|
823
|
-
Once the source checkout's pinned gentle-ai runtime (currently v4.
|
|
824
|
+
Once the source checkout's pinned gentle-ai runtime (currently v4.3.1) has written review authority, rollback MUST preserve every native store and receipt and MUST NOT run a downgraded binary against that repository. Disable the Pi route or roll forward to a compatible authority-aware release instead; deleting authority data or reinstalling an older binary is not a rollback path.
|
|
824
825
|
|
|
825
826
|
### FINALIZE wrapper input
|
|
826
827
|
|
|
@@ -1006,15 +1007,41 @@ A project can still override the global default with:
|
|
|
1006
1007
|
## Model and effort assignment
|
|
1007
1008
|
|
|
1008
1009
|
```text
|
|
1009
|
-
/gentle:
|
|
1010
|
+
/gentle:profiles
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
`/gentle:profiles` opens the models screen on the profile this repository resolves: one table, with your profiles as tabs across the top. It replaces the retired `/gentle:models`, which opened the same screen.
|
|
1014
|
+
|
|
1015
|
+
```text
|
|
1016
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
1017
|
+
│ current ◉★ ▾ before-nan-202609… nan GPT-Max + New │
|
|
1018
|
+
│ ─━━━━━━━━━━━━━━───────────────────────────────────────────────────────────── │
|
|
1019
|
+
│ current Used in this session. Default for new sessions. │
|
|
1020
|
+
│ │
|
|
1021
|
+
│ ▸ Orchestrator openai-codex/gpt-6.1-sol max │
|
|
1022
|
+
│ ────────────────────────────────────────────────────────────── │
|
|
1023
|
+
│ Agent Model ▾ Effort ▾ │
|
|
1024
|
+
│ gentle-ai-explore nan/deepseek-v4-flash high │
|
|
1025
|
+
│ gentle-ai-worker nan/glm5.3-flash high │
|
|
1026
|
+
│ │
|
|
1027
|
+
│ [ Use in this session ] [ Make default ] [ Save ] Saved │
|
|
1028
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
1010
1029
|
```
|
|
1011
1030
|
|
|
1012
|
-
|
|
1031
|
+
- **Tabs are profiles.** Click a tab or press `←` `→` to show another one; the screen redraws in place. Symbols show where a profile is in effect: `◉` this session, `★` the default for new sessions, `⌂` this repository. Leaving a profile with unsaved changes asks first: **Save and switch**, **Discard**, or **Stay**.
|
|
1032
|
+
- **The table is that profile's routing.** The orchestrator is the first row; agents follow. Click a model or press `enter` to choose from a searchable list (the current one is marked `✓`; **Custom model id…** takes any `provider/model`). Click an effort or press `e` to pick from a single row of levels: only the levels that row's model supports, as its provider's catalog declares them (every level when the row inherits its model or the model is not in the catalog). Pi lands an unsupported level on the nearest supported one at launch, and the table says where: `max → high`. Click `Model ▾` or `Effort ▾`, or move the cursor to that header, to change every agent at once; the orchestrator is never part of that.
|
|
1033
|
+
- **Three buttons decide where it applies.** **Use in this session** (`u`) binds what you see to this Pi session only and switches its orchestrator; nothing shared is written. **Make default** (`d`) makes it the default for new sessions through the guarded global apply (diff confirmation, pin honesty, rollback). **Save** (`s` or `ctrl+s`) writes what you see into the profile. Use and Make default save pending edits first and say so.
|
|
1034
|
+
- **The profile menu**, `▾` on the active tab (`m`), holds **Rename**, **Duplicate**, **Use in this repo** (the clone pin; it reads **Stop using in this repo** when it already applies), and **Delete**. **+ New** (`n`) starts a profile as a copy of the current one, from what is running now, or empty.
|
|
1035
|
+
- Problems the screen will not hide appear under the profile name with `⚠`: a pin file that is not a valid pin or names a profile that does not exist (either way it is ignored), and routing keys no agent matches (ignored at launch), with the agent name it probably meant when there is one.
|
|
1036
|
+
- Edited values are highlighted until saved, and the footer counts them (`● 2 unsaved`). `esc` closes; with unsaved edits the first press warns and the second closes without saving. Every action reports on the line under the footer.
|
|
1037
|
+
- Everything clickable highlights under the pointer, and a click runs one action. Keys: `←→` profile, `↑↓` agent, `enter` model, `e` effort, `s` save, `u` use, `d` default, `n` new, `m` the profile menu, `esc` close.
|
|
1038
|
+
|
|
1039
|
+
The editor discovers:
|
|
1013
1040
|
|
|
1014
1041
|
- project agents in `.pi/subagents/`, `.pi/agents/`, and `.agents/`;
|
|
1015
1042
|
- user agents in `~/.pi/agent/subagents/`, `~/.pi/agent/agents/`, and `~/.agents/`.
|
|
1016
1043
|
|
|
1017
|
-
When
|
|
1044
|
+
When **Make default** applies a profile, project agents write runtime profiles to `.pi/subagents.json`; global and built-in agents write profiles to `~/.pi/agent/subagents.json`.
|
|
1018
1045
|
|
|
1019
1046
|
Recommended model/effort shape:
|
|
1020
1047
|
|
|
@@ -1031,13 +1058,11 @@ Saved globally at:
|
|
|
1031
1058
|
~/.pi/gentle-ai/models.json
|
|
1032
1059
|
```
|
|
1033
1060
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
Startup and reload materialize saved non-empty routing, but never treat a saved empty agent entry (`{}`) as permission to delete an existing `subagents.json` model profile or agent frontmatter. This also preserves previously materialized routes and routes whose agent definition is missing. To clear routing, explicitly save an inherit choice in `/gentle:models` or confirm a profile replacement in `/gentle:profiles`. Activation needs no ownership sidecar or lock.
|
|
1061
|
+
Global routing is owned by profiles: edit a profile's routing on the models screen and apply it with **Make default**. Applying writes the shared global config at `~/.pi/gentle-ai/models.json`; existing project-local `.pi/gentle-ai/models.json` files are still read as a legacy fallback when no global model config exists.
|
|
1037
1062
|
|
|
1038
|
-
|
|
1063
|
+
Startup and reload materialize saved non-empty routing, but never treat a saved empty agent entry (`{}`) as permission to delete an existing `subagents.json` model profile or agent frontmatter. This also preserves previously materialized routes and routes whose agent definition is missing. To clear routing, make a profile whose entries are inherit the default (or confirm a profile replacement) on the models screen. Activation needs no ownership sidecar or lock.
|
|
1039
1064
|
|
|
1040
|
-
|
|
1065
|
+
`/gentle:profiles export-routing` writes the saved routing to `~/.pi/gentle-ai/models.export.json`, and `/gentle:profiles restore-routing` restores from that file after confirmation. They carry `-routing` because they move the global `models.json` routing, not a profile: `/gentle:profiles export <name>` and `import` move one profile through `profiles.export.json`. Export uses a versioned envelope and restore writes the normal `models.json` shape before applying routing to agents.
|
|
1041
1066
|
|
|
1042
1067
|
Config shape (per agent):
|
|
1043
1068
|
|
|
@@ -1061,32 +1086,23 @@ Legacy string entries are still accepted and treated as `model`-only config.
|
|
|
1061
1086
|
/gentle:profiles
|
|
1062
1087
|
```
|
|
1063
1088
|
|
|
1064
|
-
Profiles are named, switchable snapshots of the
|
|
1089
|
+
Profiles are named, switchable snapshots of the agent-model routing, including the orchestrator. They are the tabs of the models screen described above; everything about choosing, editing, and applying them happens there.
|
|
1065
1090
|
|
|
1066
|
-
|
|
1067
|
-
| ------- | ---------------------------------------------------------------------- |
|
|
1068
|
-
| `enter` | Bind the selected profile to this parent session. The panel shows it as `name (session)`; launches from this session resolve the binding ahead of pins and the global default, and a profile with an `orchestrator` entry switches the session you are in to that model right away. Nothing is written: no global routing, no pins, no materialized stores. |
|
|
1069
|
-
| `a` | Set as global default (the pre-binding `enter` semantics): writes `models.json`, replaces the routing of every agent, sets the orchestrator when the profile defines one. Inside a pinned repository it stays repository-scoped instead; see **Per-repository pins** below. |
|
|
1070
|
-
| `c` | Create a new, empty profile. |
|
|
1071
|
-
| `s` | Snapshot the current routing into the selected profile, including the orchestrator the session actually runs (live model and thinking level); falls back to the `settings.json` defaults when no live model exists. Live routing is unchanged. |
|
|
1072
|
-
| `d` | Duplicate the selected profile. |
|
|
1073
|
-
| `r` | Rename the selected profile (keeps it active if it was active). |
|
|
1074
|
-
| `x` | Delete the selected profile (refuses the active profile). |
|
|
1075
|
-
| `e` | Export the selected profile to `~/.pi/gentle-ai/profiles.export.json`. |
|
|
1076
|
-
| `i` | Import a profile from `~/.pi/gentle-ai/profiles.export.json`. |
|
|
1077
|
-
| `p` | Pin the selected profile to this repository: writes the clone-local pin, so this repository's subagent launches use that profile no matter which profile is globally active. Pressing it again on the pinned profile removes the pin. |
|
|
1078
|
-
| `P` | Publish or remove the shared repository declaration at `<worktree-root>/.pi/gentle-ai/profile.json`, so the whole team starts from that profile in this repository. |
|
|
1079
|
-
| `j`/`k`, wheel | Scroll the detail pane one line at a time (agents-view style). |
|
|
1080
|
-
| `pgup`/`pgdn`, `ctrl+j`/`ctrl+k` | Scroll the detail pane by a page. |
|
|
1081
|
-
| `esc` | Close. |
|
|
1091
|
+
The file operations are subcommands:
|
|
1082
1092
|
|
|
1083
|
-
|
|
1093
|
+
| Command | Action |
|
|
1094
|
+
| ------------------------------------ | ------ |
|
|
1095
|
+
| `/gentle:profiles export <name>` | Export a profile to `~/.pi/gentle-ai/profiles.export.json`. |
|
|
1096
|
+
| `/gentle:profiles import` | Import the profile in `~/.pi/gentle-ai/profiles.export.json`, asking before it replaces one with the same name. |
|
|
1097
|
+
| `/gentle:profiles publish <name>` | Publish the shared repository declaration at `<worktree-root>/.pi/gentle-ai/profile.json` so the whole team starts from that profile; run it again to remove the declaration. |
|
|
1084
1098
|
|
|
1085
|
-
|
|
1099
|
+
The binding made by **Use in this session** writes no shared routing: not `models.json`, Pi's global `settings.json`, agent frontmatter, `subagents.json`, or repository pins. When the table has unsaved edits, they are saved to the profile in `profiles.json` first, exactly as **Save** would, and the screen says so; with no pending edits nothing is written at all. Other open sessions keep their own bindings and live orchestrators. The session binding overrides pins and global routing as a complete snapshot, including reviewer routing; omitted roles do not fall back to another profile. The binding lasts in the current process (including `/reload`); resuming in another process requires selecting it again. Re-selecting re-copies the profile definition from `profiles.json`; later edits to `subagents.json` or agent frontmatter never reach a bound session, in that session or through a re-selection.
|
|
1086
1100
|
|
|
1087
|
-
|
|
1101
|
+
Outside a pinned repository, **Make default** writes `~/.pi/gentle-ai/models.json`, then reconciles agent frontmatter and `subagents.json` with the shared materialization rules. When a valid pin wins, it only re-pins this clone to the profile and writes none of `models.json`, materialized routing, `settings.json`, or the active marker (see **Per-repository pins**). A profile is a complete snapshot: every discoverable agent it omits returns to inherit, so routing materialized by a previous profile, by an earlier apply, or by a migration never survives a switch silently. The active profile is persisted so `/gentle:profiles` reopens with the applied profile marked.
|
|
1088
1102
|
|
|
1089
|
-
|
|
1103
|
+
A profile also carries the orchestrator under the reserved routing key `orchestrator`. Outside a pinned repository, **Make default** on a profile that defines one writes `defaultProvider`, `defaultModel`, and `defaultThinkingLevel` to Pi's global `settings.json` (preserving every other key; an unreadable `settings.json` aborts that part and is reported instead of being overwritten) and switches the session you are in to that model and thinking level right away, so the orchestrator answers with the profile's model from the next turn. **Use in this session** skips the settings write and switches only the session you are in: same live move, nothing persisted. When the model is not in Pi's catalog or its provider has no authentication, **Make default** still records the default for new sessions and says this session kept its current model, while **Use in this session** simply reports the refusal. Applying or binding a profile without an `orchestrator` entry never moves the orchestrator, and **+ New › From what's running now** captures the orchestrator the session actually runs together with the routing. `orchestrator` is reserved: it is not a subagent name, is never written to `subagents.json`, and is not counted as a role.
|
|
1104
|
+
|
|
1105
|
+
The `current` seed and **From what's running now** read the routing in effect. A valid local pin or repository declaration wins first: inside a pinned repository they read the pinned profile's routing. **From what's running now** also prefers this session's binding when it has one. Otherwise they read `models.json` where it has an entry, and the `subagents.json` model profile or frontmatter routing the runtime actually resolves for agents it omits. A sparse `models.json` therefore never hides routing that is still live. When `profiles.json` is missing, the command seeds one profile named `current` captured from that effective routing, marked active only when it has routing entries. Profiles or routing entries dropped by normalization are named in a warning instead of being lost silently.
|
|
1090
1106
|
|
|
1091
1107
|
Saved globally at:
|
|
1092
1108
|
|
|
@@ -1119,7 +1135,7 @@ Store shape:
|
|
|
1119
1135
|
|
|
1120
1136
|
The `profiles` values use the same per-agent shape as `models.json`. Profile names are slugs of 1-64 ASCII characters (letters, numbers, `.`, `_`, `-`, starting with a letter or number); names outside ASCII are rejected, as are the reserved object keys `__proto__`, `constructor`, and `prototype`. A rename or duplicate onto an existing name is refused, renaming the active profile keeps it active, and deleting the active profile is refused. Export and import use a single-profile envelope (`kind: "gentle-pi.agent_model_profile"`, `version: 1`) at `~/.pi/gentle-ai/profiles.export.json`.
|
|
1121
1137
|
|
|
1122
|
-
The store is replaced atomically through a sibling temp file and a rename, so an interrupted write cannot leave truncated JSON behind.
|
|
1138
|
+
The store is replaced atomically through a sibling temp file and a rename, so an interrupted write cannot leave truncated JSON behind. **Make default** writes `profiles.json` first and then materializes routing; if materialization fails, the previous active marker is restored, and the previous routing is restored when a profile was active before. With no previously active profile there is no routing to restore: `models.json` keeps the new routing and the warning says so. Anything that could not be restored is named in the warning.
|
|
1123
1139
|
|
|
1124
1140
|
### Per-repository pins
|
|
1125
1141
|
|
|
@@ -1129,8 +1145,8 @@ Two pin layers exist, and both hold only a profile name:
|
|
|
1129
1145
|
|
|
1130
1146
|
| Layer | Path | Written by | Git impact |
|
|
1131
1147
|
| ----- | ---- | ---------- | ---------- |
|
|
1132
|
-
| Local pin | `<git-common-dir>/gentle-ai/profile-pin.json` |
|
|
1133
|
-
| Repository declaration | `<worktree-root>/.pi/gentle-ai/profile.json` |
|
|
1148
|
+
| Local pin | `<git-common-dir>/gentle-ai/profile-pin.json` | Profile menu `▾` › **Use in this repo** | Invisible to git; every worktree of the clone shares it. |
|
|
1149
|
+
| Repository declaration | `<worktree-root>/.pi/gentle-ai/profile.json` | `/gentle:profiles publish <name>` | An ordinary repository file; commit it to share the pin with the team. |
|
|
1134
1150
|
|
|
1135
1151
|
Both use the same shape, and both are a separate artifact from `profiles.json`:
|
|
1136
1152
|
|
|
@@ -1150,9 +1166,9 @@ or stale pins fall through to the next valid layer. A session shows the profile
|
|
|
1150
1166
|
in `follow` mode, appears within about two seconds while the UI session is active. The indicator is
|
|
1151
1167
|
omitted if no valid profile remains.
|
|
1152
1168
|
|
|
1153
|
-
For a given working directory the winner is the local pin, then the repository declaration, then the globally active profile. A session resolves these layers once, when it starts, and keeps the result.
|
|
1169
|
+
For a given working directory the winner is the local pin, then the repository declaration, then the globally active profile. A session resolves these layers once, when it starts, and keeps the result. Both are toggles: using one on the profile that already holds that layer removes it (the menu then reads **Stop using in this repo**), and either one outside a Git worktree writes nothing and says so.
|
|
1154
1170
|
|
|
1155
|
-
In a pinned repository the pinned profile governs subagent launches: the agents it names take its model and effort, and the agents it omits return to inherit (their own definition, then the default model). The
|
|
1171
|
+
In a pinned repository the pinned profile governs subagent launches: the agents it names take its model and effort, and the agents it omits return to inherit (their own definition, then the default model). The default profile does not reach those launches, which `/gentle:profiles` reports when it runs inside a pinned repository. **Make default** follows the same boundary: when a valid pin wins it re-pins this clone (the clone-local pin) instead of writing the global routing; a malformed pin or one naming a missing profile is ignored, and Make default applies globally as it would outside a pinned repository, so it can never move another repository's routing. A committed repository declaration is never rewritten; when one still names another profile, the clone-local pin takes precedence and the screen says so. **Use in this session** writes no pin or shared routing (only pending table edits, saved to the profile first): it binds the profile to the current session, which outranks the pin for this session's launches. The tab of the pinned profile carries `⌂`.
|
|
1156
1172
|
|
|
1157
1173
|
To share a pin, commit the repository declaration. When `.pi/` is ignored, Git cannot re-include a nested file until its parent directories are visible. The panel therefore prints these ordered root `.gitignore` rules, which keep unrelated `.pi` content ignored while making only the declaration committable:
|
|
1158
1174
|
|
|
@@ -1164,7 +1180,7 @@ To share a pin, commit the repository declaration. When `.pi/` is ignored, Git c
|
|
|
1164
1180
|
!.pi/gentle-ai/profile.json
|
|
1165
1181
|
```
|
|
1166
1182
|
|
|
1167
|
-
Renaming the profile that is this repository's local pin rewrites the local pin; a repository declaration is never rewritten behind a commit, and the
|
|
1183
|
+
Renaming the profile that is this repository's local pin rewrites the local pin; a repository declaration is never rewritten behind a commit, and the rename note says to run `/gentle:profiles publish <name>` again when it still names the old profile. Deleting a profile is refused while it is the global active profile, this repository's local pin, or this repository's repository declaration. Pins held by other repositories cannot be enumerated from here and are not checked.
|
|
1168
1184
|
|
|
1169
1185
|
A pin that cannot be honored never blocks work and is never destroyed by a read. Running outside a Git worktree, an unreadable or unparseable pin file, and a pin naming a profile the global store does not have are reported in the panel, and the repository falls back to the globally active profile. A missing pin layer is the ordinary no-pin state and stays silent.
|
|
1170
1186
|
|
|
@@ -1187,7 +1203,7 @@ A session that never selected a profile resolves the shared defaults once, at st
|
|
|
1187
1203
|
**Drift notice.** On each subagent launch, a session with a frozen profile compares it with the current defaults of its own directory, without applying them. When they differ, it shows one line:
|
|
1188
1204
|
|
|
1189
1205
|
```text
|
|
1190
|
-
el Gentleman: the default profile changed to "local" (local), this session keeps "frontier" (local).
|
|
1206
|
+
el Gentleman: the default profile changed to "local" (local), this session keeps "frontier" (local). Open /gentle:profiles and choose Use in this session to adopt one.
|
|
1191
1207
|
```
|
|
1192
1208
|
|
|
1193
1209
|
The notice appears once per distinct change: further launches stay quiet until the defaults change again. The same profile reached through another layer is not a change; an edit of the profile's content is. Sessions with a profile selected in the session, `follow` sessions, and subagent children never show it.
|
|
@@ -1208,8 +1224,7 @@ The notice appears once per distinct change: further launches stay quiet until t
|
|
|
1208
1224
|
| -------------------------------- | ------------------------------------------------------------------- |
|
|
1209
1225
|
| `/gentle:status` | Shows package assets and global model config status. |
|
|
1210
1226
|
| `/gentle:doctor` | Runs read-only diagnostics for assets, model/persona config, memory tools, safety guards, and (inside Herdr) the task-summary sidebar setup. |
|
|
1211
|
-
| `/gentle:
|
|
1212
|
-
| `/gentle:profiles` | Opens global agent-model profiles: apply live, create, snapshot, duplicate, rename, delete, export, and import. |
|
|
1227
|
+
| `/gentle:profiles` | Opens the models screen on this repository's profile. `export <name>`, `import`, and `publish <name>` handle profile files and the repository declaration; `export-routing` and `restore-routing` move the saved global routing through `models.export.json`. |
|
|
1213
1228
|
| `/gentle:commands` | Opens the command palette (default `alt+k`): a curated, grouped menu (Configuration, Session, Diagnostics, Skills) of registered Gentle commands; search and run by label. |
|
|
1214
1229
|
| `/gentle:persona` | Switches global persona mode, with project override support. |
|
|
1215
1230
|
| `/gentle:background-subagents` | Shows or sets the managed background-subagents policy (`status\|enable\|disable`), naming the source that decided it. |
|
|
@@ -1249,6 +1264,8 @@ With the policy `on`, `subagent_run` defaults to `mode: "background"` at the run
|
|
|
1249
1264
|
|
|
1250
1265
|
Background delegation is off unless you turn it on. The policy is user-owned: only an explicit `/gentle:background-subagents enable` or `disable` writes it, and Pi automation never toggles it.
|
|
1251
1266
|
|
|
1267
|
+
An agent whose explicit `tools` frontmatter includes `bash_background` fails before spawn when the effective background-subagents policy is `off`, in either task or background mode. Admission resolves policy at dispatch using the request's environment and config home, including queued tasks. The error names the policy file, the exact opt-in shape `{"schema":"gentle-pi.background-subagents/v1","policy":"on"}`, and `/gentle:background-subagents enable|disable|status`. Agents without explicit tools are unchanged; the child missing-tools check remains the backstop for other names. Policy `on` passes this admission check only: it does not implement child background tools (future Slices 2–3).
|
|
1268
|
+
|
|
1252
1269
|
```text
|
|
1253
1270
|
/gentle:background-subagents Report the effective policy, the deciding source, and the resolved capability.
|
|
1254
1271
|
/gentle:background-subagents enable Write "on" to the global file.
|
|
@@ -1330,7 +1347,7 @@ The frame labels INSERT, NORMAL, VISUAL (characterwise), or VISUAL LINE (linewis
|
|
|
1330
1347
|
|
|
1331
1348
|
**Deliberate `/` divergence from Claude Code:** NORMAL `/` hands off to **Pi's native slash commands and skills**, enters INSERT, and inserts `/` at the existing cursor. Pi offers slash completion only at the start of the first line; elsewhere it inserts a literal slash without moving or replacing the draft. There is **no reverse prompt-history search**. Pi's explicit history shortcuts still work, transferring to INSERT first. Unknown NORMAL printable input, encoded text and bracketed paste do not silently insert; application shortcuts can transfer to INSERT before acting.
|
|
1332
1349
|
|
|
1333
|
-
This is a bounded command subset, not full Claude Code/Vim parity. The private editor adapter supports only the audited Pi coding-agent/TUI `0.99.1`, `0.99.2`, `1.0.0`, `1.1.0`, and `1.
|
|
1350
|
+
This is a bounded command subset, not full Claude Code/Vim parity. The private editor adapter supports only the audited Pi coding-agent/TUI `0.99.1`, `0.99.2`, `1.0.0`, `1.1.0`, `1.2.0`, `1.3.0`, and `1.4.0` package pairs. The two 0.99 releases have byte-identical editor and undo-stack sources. Pi 1.0.0, 1.1.0 and 1.2.0 are separately audited against the touched state, paste/history, cursor/layout, autocomplete and undo-snapshot contracts. Pi 1.2.0's paired APC fake-cursor markers remain intact so the host can suppress software cursors when hardware cursors are visible; selection inversion and empty-prompt hints support both these markers and legacy SGR cursors. Current bundled and unbundled 1.2.0 tests prove identity, edit/undo, paste, selection, wrapping/scroll and autocomplete behavior, not old/new byte identity. Fabricated metadata tests preserve exact-version admission coverage for the older audited releases. Version metadata must come from a canonical candidate host package root whose actual `CustomEditor` and `Editor` classes match the loaded classes, never from the extension's local metadata or CLI path alone. Unknown versions, mismatched prototypes, or invalid layouts fail closed: a single compatibility warning is shown and the prompt continues with ordinary editing instead of silently entering inert NORMAL mode. Operations that would cross a registered collapsed paste marker, or encounter duplicate occurrences of a registered marker ID, are rejected without editing it. Visual highlighting relies on Pi's render layout and may be omitted if its geometry cannot be validated. No live-terminal proof of every layout or complete parity is claimed.
|
|
1334
1351
|
|
|
1335
1352
|
Startup banner settings remain global in `banner.json` under `GENTLE_PI_CONFIG_HOME` (default `~/.pi/gentle-ai`). Existing `showRose` and `showTextLogo` opt-outs independently control the main startup artwork; both default to enabled. Changes apply on the next session or `/reload`. Color presets are `pink` (default), `cyan`, `yellow`, and `green`. The static sidebar heading is independent of these preferences and follows the active theme.
|
|
1336
1353
|
|
|
@@ -37,3 +37,29 @@ does not establish persistence. The newest profile-family entry is terminal:
|
|
|
37
37
|
Replay neither appends nor publishes bindings and never applies a model or
|
|
38
38
|
thinking level. A subsequent disk-reader slice supplies corroboration; this
|
|
39
39
|
codec alone cannot establish it.
|
|
40
|
+
|
|
41
|
+
## Disk corroboration
|
|
42
|
+
|
|
43
|
+
`readSessionProfileDisk(source)` in `lib/session-profile-disk-reader.ts` is the
|
|
44
|
+
stateless synchronous check that supplies the corroboration replay requires.
|
|
45
|
+
It reads the session's public active branch and its JSONL file, selects the
|
|
46
|
+
newest profile-family entry on the branch (excluding caller-supplied known
|
|
47
|
+
failed append IDs), and admits it only when the record on disk is identical.
|
|
48
|
+
It performs no writes, fallback policy, caching, ancestry repair or fsync, and
|
|
49
|
+
a missing file is conservative: it never restores a profile found only in
|
|
50
|
+
memory.
|
|
51
|
+
|
|
52
|
+
The result is the decoder result plus `entryIndex` and `lineNumber`, or
|
|
53
|
+
`indeterminate` with one reason: `missing-source`, `invalid-candidate-metadata`,
|
|
54
|
+
`unreadable-file`, `source-changed`, `invalid-record`,
|
|
55
|
+
`session-header-mismatch`, `duplicate-id`, `missing-header`,
|
|
56
|
+
`selected-record-missing`, `selected-record-mismatch`, or
|
|
57
|
+
`unserializable-source` (exported as `DiskProfileIndeterminateReason`).
|
|
58
|
+
Reasons never carry record contents.
|
|
59
|
+
|
|
60
|
+
Malformed JSON lines are skipped, matching Pi's session parser, so a file Pi
|
|
61
|
+
opens never becomes permanently indeterminate here; `lineNumber` still counts
|
|
62
|
+
physical lines. A malformed selected record is therefore
|
|
63
|
+
`selected-record-missing`. `missing-header` means no line parsed at all (an
|
|
64
|
+
empty, all-blank or all-malformed file). Pi writes no byte order mark, so a
|
|
65
|
+
BOM-prefixed header line is skipped as malformed like any other.
|