gentle-pi 4.3.0 → 4.4.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 +8 -5
- 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 +101 -151
- 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 +61 -0
- package/docs/gentle-shell.md +77 -7
- package/docs/install-wizard.md +30 -6
- package/docs/permission-modes.md +7 -2
- package/docs/readme-reference.md +19 -15
- 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 +173 -38
- package/extensions/gentle-ai.ts +214 -69
- package/extensions/gentle-design.ts +158 -0
- package/extensions/gentle-music.ts +289 -0
- package/extensions/gentle-shell.ts +332 -73
- 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 +2 -0
- 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 +123 -49
- package/lib/gentle-shell-launcher.ts +9 -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/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-persistence.ts +15 -7
- package/lib/session-scratch.ts +52 -3
- package/lib/session-worktree-registry.ts +7 -0
- package/lib/shell-bar.ts +4 -3
- package/lib/shell-changes.ts +81 -5
- package/lib/shell-prompt.ts +4 -4
- package/lib/shell-sidebar-layout.ts +26 -6
- package/lib/shell-todo.ts +1 -1
- package/lib/verifier-admission.ts +5 -4
- package/lib/vim-editor-adapter.ts +11 -8
- 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 +122 -48
- package/runtime/gentle-shell-launcher.mjs +9 -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/gentle-ai-installer.mjs +10 -10
- package/scripts/installer-downloads.mjs +7 -7
- package/scripts/installer-preflight.mjs +5 -3
- package/scripts/installer-windows.mjs +37 -7
- package/scripts/main-channel.mjs +91 -17
- package/scripts/pi-update.mjs +34 -6
- 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 +3 -3
- package/tests/clipboard-image.test.ts +114 -0
- package/tests/command-palette.test.ts +1 -1
- 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 +365 -20
- package/tests/gentle-ai-binary.test.ts +1 -1
- package/tests/gentle-ai-installer.test.ts +51 -51
- package/tests/gentle-ai.test.ts +292 -13
- package/tests/gentle-design.test.ts +1313 -0
- package/tests/gentle-music.test.ts +335 -0
- package/tests/gentle-shell-bundled.test.ts +301 -248
- package/tests/gentle-shell-launcher.test.ts +28 -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 +183 -8
- 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-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/main-channel-upgrade.test.ts +232 -2
- package/tests/main-channel.test.ts +140 -21
- 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 +99 -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/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-scratch.test.ts +68 -2
- package/tests/session-worktree-registry.test.ts +13 -1
- package/tests/shell-bar.test.ts +14 -2
- 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 +50 -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/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/bundled-install.md
CHANGED
|
@@ -13,7 +13,7 @@ The building blocks live in `scripts/bundled-install.mjs`. The web installer and
|
|
|
13
13
|
| `~/.gentle-shell/npm/{prefix,cache}/`, `~/.gentle-shell/npm/npmrc` | npm's global prefix, cache and global config. The global config file is never written. |
|
|
14
14
|
| `~/.gentle-shell/runtime/pnpm-11.1.1/package/` | Our pnpm, from the verified registry tarball. |
|
|
15
15
|
| `~/.gentle-shell/runtime/go/1.25.14/go/` | Our Go, only when asked (`acquireGo` layout). |
|
|
16
|
-
| `~/.gentle-shell/runtime/engram-3.
|
|
16
|
+
| `~/.gentle-shell/runtime/engram-3.5.2/engram` | Our Engram, from the verified GitHub release archive ([Isolation from the user's Gentle AI](#isolation-from-the-users-gentle-ai)). |
|
|
17
17
|
| `~/.gentle-shell/gentle-ai/` | Gentle AI's state, managed assets, backups and telemetry state (`GENTLE_AI_HOME`). |
|
|
18
18
|
| `~/.gentle-shell/config/gentle-ai/` | gentle-pi's config home in a bundled install (derived, never exported to Pi): profiles, preferences, persona, background subagents. |
|
|
19
19
|
| `~/.gentle-shell/pnpm/{store,cache,state,config}/` | Every folder pnpm writes. |
|
|
@@ -24,6 +24,25 @@ The building blocks live in `scripts/bundled-install.mjs`. The web installer and
|
|
|
24
24
|
|
|
25
25
|
On Windows the same layout lives under a private folder. The module tries `%LOCALAPPDATA%\gentle-shell` first. It falls back to `%USERPROFILE%\.gentle-shell-bundle` only when an untrusted owner or ACL rejects the first folder, the same rule the bootstrap uses for its tools. The folder is claimed with the bootstrap's protected DACL and marked with `.gentle-shell-bundle` (`ensureWindowsPrivateFolder`). `current` is a pointer file holding the version id. The launcher is `bin\gentle-shell.cmd`, and `tmp\` holds TEMP and TMP for pnpm's children. The agent home stays at `%USERPROFILE%\.gentle-shell\agent`.
|
|
26
26
|
|
|
27
|
+
### Windows prerequisite failure diagnostics
|
|
28
|
+
|
|
29
|
+
`windowsProcessCheck` still throws exactly `Windows prerequisite process failed`
|
|
30
|
+
(`process-failed` classification). Its standard Error cause preserves status,
|
|
31
|
+
signal and selected process-error fields plus bounded stdout/stderr. A sanitized
|
|
32
|
+
`cause.stack` also carries these fields for existing evidence consumers, without
|
|
33
|
+
local callsites, raw spawn errors, commands, argv or environment snapshots.
|
|
34
|
+
Process-error messages use only a sanitized native error code or fixed fallback,
|
|
35
|
+
never raw spawn text that could include a private bare executable name.
|
|
36
|
+
Limits are UTF-16 code units: streams1024 each, error message256, name/code/errno
|
|
37
|
+
text64, signal32 and cause stack8192; numeric status/errno remain numeric.
|
|
38
|
+
Path/SID, encoded ACL/opaque and control-bearing lines are suppressed; credential
|
|
39
|
+
markers, including underscore-separated environment names such as `GITHUB_TOKEN`
|
|
40
|
+
and `API_KEY`, suppress the entire field including continuation lines. This conservative
|
|
41
|
+
filter may discard useful output and is not a general-purpose secret parser.
|
|
42
|
+
Nothing prints automatically. CMD/BAT rejection, neutral cwd, shell=false,
|
|
43
|
+
15-second SIGKILL/1MiB capture and all ACL/provenance checks remain unchanged.
|
|
44
|
+
Elapsed time alone does not establish timeout or diagnose the historical CI failure.
|
|
45
|
+
|
|
27
46
|
## Ownership rules
|
|
28
47
|
|
|
29
48
|
- **Runtimes.** Each one is downloaded through `verifiedDownload` (the existing pins and hashes), written to a staging folder and run once to check its version. It is then marked with `.gentle-shell-runtime` and published with one rename. A marked runtime is reused. An unmarked folder is never replaced. Renaming is safe here because the extracted trees hold only regular files and folders, never links. The pnpm tarball's executable bits (`bin/pnpm.mjs`, `dist/node-gyp-bin/node-gyp`) are kept, for the owner only.
|
|
@@ -229,68 +248,55 @@ Dropped: inherited npm and pnpm settings, `NODE_OPTIONS`, `NODE_PATH`, and the w
|
|
|
229
248
|
|
|
230
249
|
### Engram startup safety
|
|
231
250
|
|
|
232
|
-
A bundled Shell
|
|
251
|
+
A bundled Shell shares the global Engram server, like other agents' hooks: it reuses a verified server already listening on the default endpoint and, when nothing listens, starts one itself with its verified bundled core. It decides before setup and again right before Pi starts. When memory may not be used, Shell keeps working without memory and **points `ENGRAM_BIN` at its own guard**, so no provider, whichever Pi route loaded it, can open, create or migrate a store directly. The core pin is **3.5.2**, acquired through the existing size- and checksum-verified path.
|
|
233
252
|
|
|
234
253
|
#### Decision
|
|
235
254
|
|
|
236
255
|
| Evidence (default `~/.engram`, default endpoint `127.0.0.1:7437`) | Memory | `ENGRAM_BIN` / `ENGRAM_URL` |
|
|
237
256
|
|---|---|---|
|
|
238
|
-
|
|
|
239
|
-
|
|
|
240
|
-
|
|
|
241
|
-
|
|
|
242
|
-
|
|
|
243
|
-
|
|
|
244
|
-
| Explicit `ENGRAM_BIN`, `ENGRAM_URL`, `ENGRAM_PORT`, `ENGRAM_DATA_DIR`, `ENGRAM_DATABASE_URL`, or an invalid `ENGRAM_STARTUP_POLICY` | Disabled, never probed | Explicit `ENGRAM_BIN`/`ENGRAM_URL` kept; `ENGRAM_URL` alone gets the verified core (or the guard) as `ENGRAM_BIN`; otherwise guard |
|
|
257
|
+
| Running server answers the exact `GET /compatibility` ready contract | Allowed; reuse that server unchanged | Guard + `ENGRAM_URL=http://127.0.0.1:7437` |
|
|
258
|
+
| Nothing listening, verified bundled core | Allowed once the server Shell starts (below) answers ready; otherwise disabled for that launch | Guard + `ENGRAM_URL=http://127.0.0.1:7437` |
|
|
259
|
+
| Nothing listening, but `engram.db`'s header `user_version` is newer than the bundled core's schema | Disabled; no server is started | Guard |
|
|
260
|
+
| Nothing listening, but the bundled core is missing or unverified | Disabled | Guard (never an `engram` from `PATH`) |
|
|
261
|
+
| Anything else listening: a different service, timeout, 401/404, an older server, malformed answers | Disabled; the listener is never stopped or replaced | Guard |
|
|
262
|
+
| Explicit `ENGRAM_BIN`, `ENGRAM_URL`, `ENGRAM_PORT`, `ENGRAM_SOCKET`, `ENGRAM_DATA_DIR`, `ENGRAM_DATABASE_URL`, `ENGRAM_SERVER_MODE`, or an invalid `ENGRAM_STARTUP_POLICY` | Disabled, never probed or started | Explicit `ENGRAM_BIN`/`ENGRAM_URL` kept; `ENGRAM_URL` alone gets the verified core (or the guard) as `ENGRAM_BIN`; otherwise guard |
|
|
245
263
|
|
|
246
|
-
|
|
264
|
+
An existing store at `~/.engram` does not disable memory by itself, whoever created it (an earlier Shell or the global Engram CLI): the server owns the store, and Shell only talks to a server that proves itself through `/compatibility`. The one exception is the header tripwire: when `engram.db` is a regular, unlinked file whose first 100 bytes are a valid SQLite header (magic, page size, bytes 18/19 each 1 or 2) and whose `user_version` (bytes 60-63) is **greater** than the bundled core's schema (`1`, verified from `v3.5.2:internal/store/store.go`), a newer Engram migrated the store, so Shell does not start its older core on it. Start that newer Engram's server yourself; Shell then reuses it. A pin without a verified schema entry treats any readable header as newer. Equal or lower (including a stale `0` before a WAL checkpoint) is no signal either way.
|
|
247
265
|
|
|
248
|
-
|
|
266
|
+
Classification never runs an Engram executable, never opens SQLite, and never infers compatibility from a version string. It reads the raw database header and makes bounded (1 s) read-only `GET /compatibility` and `GET /health` requests to the default endpoint on a direct loopback socket, without proxy, redirects or credentials. `gentle-shell --version` and a Pi version or help flag (`--version`, `-v`, `--help`, `-h` where Pi reads it as a flag: before Pi's own `--` and not as another option's value, so a prompt or option value containing `-v` does not count) never probe, start a server, ensure the companion or print memory notices. A Pi subcommand (`gentle-shell list`, `install`, ...) and `gentle-shell setup` never start a server either.
|
|
249
267
|
|
|
250
|
-
|
|
268
|
+
#### Starting the shared server
|
|
251
269
|
|
|
252
|
-
-
|
|
253
|
-
- **Windows.** The guard has no `.exe`; spawning it fails (for example `ENOENT` or `EINVAL`), which still fails closed, but no notice is printed.
|
|
270
|
+
Only the final pre-Pi decision starts a server. Shell runs the verified bundled core as plain `engram serve`, with Engram's own default port and data directory, **detached** (its own process group, `stdio` ignored, unreferenced, `windowsHide` on Windows, working directory the home folder), so it outlives Pi like a server other agents' hooks start. Its environment is the user's minus every `ENGRAM_*` setting and `GH_TOKEN`/`GITHUB_TOKEN`, plus `ENGRAM_NO_UPDATE_CHECK=1`. For `TMPDIR`/`TMP`/`TEMP` whose final path component is session scratch (`gp` or `ga` followed by exactly six alphanumeric characters), POSIX drops the setting. Windows instead explicitly replaces it with its original absolute ancestor outside consecutive scratch components: omitting `TEMP` can cause Node to inherit the parent's scratch again. When any Windows scratch setting is replaced and `TEMP` is absent, Shell also sets `TEMP` to that stable ancestor. Existing custom temp settings retain their own values, even when they name different roots. Windows path separators and case-insensitive environment keys are supported. An unsafe relative scratch path disables this startup attempt before spawning; Shell never guesses a root or creates a temp folder. Unrelated variables remain unchanged. Pi keeps the user's environment. Shell then polls `GET /compatibility` for up to 10 seconds. A ready answer allows memory through the reuse URL; otherwise (the core fails to start, exits, or never answers ready) memory is disabled for that launch with a notice, and Shell still starts Pi. Concurrent launches converge: when the child exits (for example because another launch won the bind), Shell keeps polling for a short grace, and a ready `/compatibility` from the winner counts as started. Shell never stops a server it started or found; it keeps running for every client until you stop it.
|
|
254
271
|
|
|
255
|
-
####
|
|
256
|
-
|
|
257
|
-
When the final pre-Pi decision is "fresh" (no data directory, nothing listening, verified bundled core, no explicit selection), Shell provisions the store identity itself **before** Pi starts: it runs the verified bundled core's `instance-id` (15 s timeout) with the environment Pi will use, except that this one invocation gets `ENGRAM_NO_UPDATE_CHECK=1` and no `GH_TOKEN`/`GITHUB_TOKEN`. In Engram 3.4.0 that command only creates the data directory, `.instance-id.lock` and `.instance-id`; it skips orphan migration and opens no database. Shell then reads the `.instance-id` **file** (regular, not a link, a valid id equal to the command's output, in the same default directory it classified as absent) and immediately writes `<prefix>/config/engram-provenance.json` (mode 0600): the canonical data directory, that instance id, and the sha256 of the bundled core. If any step fails (the command fails or times out, the identity is invalid, or the record cannot be written), memory is disabled for that launch behind the guard; Pi never starts with memory allowed without a written record. Shell never records a store it did not provision, so a store that appears later at the default directory is never adopted.
|
|
272
|
+
#### The guard
|
|
258
273
|
|
|
259
|
-
|
|
274
|
+
`bin/engram-guard` is a POSIX `sh` script, run directly (no shell needed by the caller). It ignores its arguments, prints `ENGRAM_STARTUP_NOTICE` (as data, never executed) to stderr and exits 78. It never runs Engram and never reads or writes Engram data. gentle-engram 0.4.1 reaches local data only by running `ENGRAM_BIN` (`instance-id` first, before any health probe or spawn), so the guard stops it before any store access; 0.4.2 also honors `ENGRAM_STARTUP_POLICY=disabled`, and with `ENGRAM_URL` it talks to the shared server over HTTP. Pi, its subagents and the agent's shell all inherit the same environment.
|
|
260
275
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
3. If a server listens, its `/health` reports the recorded instance and exactly the bundled core version.
|
|
276
|
+
- **Explicit selections bypass the guard.** An `ENGRAM_BIN` or `ENGRAM_URL` you set is never replaced or removed (with only `ENGRAM_URL`, `ENGRAM_BIN` is still the verified core, or the guard without one, never a `PATH` engram); memory is still marked disabled through the policy, which only 0.4.2+ honors. An `ENGRAM_SERVER_MODE` you set is passed through untouched; Shell never selects one.
|
|
277
|
+
- **Windows.** The guard has no `.exe`; spawning it fails (for example `ENOENT` or `EINVAL`), which still fails closed, but no notice is printed.
|
|
264
278
|
|
|
265
279
|
#### Compatible reuse and authorization
|
|
266
280
|
|
|
267
|
-
`GET /compatibility` (published in Engram 3.4.0 through PR #1792; 3.3.2 answers 404) must return `status: "ready"`, `active_reuse_authorized: true`, `capability: "startup-verified-store-v1"`, `revision: 1`, `source: "active"`, 32-hex `instance_id` and `runtime_id`, and no `offline_automatic_opening_authorized: true`. The endpoint uses the server's `requireAuth`: open when the **server** has no `ENGRAM_HTTP_TOKEN`, otherwise it needs `Authorization: Bearer <token>`. Shell owns no such secret and sends none, so a token-protected server answers 401 and stays unknown (disabled).
|
|
281
|
+
`GET /compatibility` (published in Engram 3.4.0 through PR #1792; 3.3.2 answers 404) must return `status: "ready"`, `active_reuse_authorized: true`, `capability: "startup-verified-store-v1"`, `revision: 1`, `source: "active"`, 32-hex `instance_id` and `runtime_id`, and no `offline_automatic_opening_authorized: true`. Engram 3.5.2's plain `serve` answers exactly this. The endpoint uses the server's `requireAuth`: open when the **server** has no `ENGRAM_HTTP_TOKEN`, otherwise it needs `Authorization: Bearer <token>`. Shell owns no such secret and sends none, so a token-protected server answers 401 and stays unknown (disabled). The server Shell starts never inherits `ENGRAM_HTTP_TOKEN`.
|
|
268
282
|
|
|
269
283
|
#### Recovery and setup
|
|
270
284
|
|
|
271
|
-
When the running server's `/health` reports a valid 32-hex `instance_id` and a canonical numeric `x.y.z` version (optional `v` prefix, no leading zeros, at most four digits per component) older than 3.4.0, and `/compatibility` does not answer ready, the notice names that version and asks to back up the data, update **that server** to 3.4.0 or later with its own installation method, and restart it. The version only selects this wording: memory stays disabled, and any other version string is never shown. Otherwise, when disabled, Shell explains that it **could not verify safe
|
|
285
|
+
When the running server's `/health` reports a valid 32-hex `instance_id` and a canonical numeric `x.y.z` version (optional `v` prefix, no leading zeros, at most four digits per component) older than 3.4.0, and `/compatibility` does not answer ready, the notice names that version and asks to back up the data, update **that server** to 3.4.0 or later with its own installation method, and restart it. The version only selects this wording: memory stays disabled, and any other version string is never shown. Otherwise, when disabled, Shell explains that it **could not verify safe server reuse**. Matching versions or updating alone do not prove compatibility. Back up existing data before manual changes; do not delete the store or bypass the safety check. Shell rechecks on every launch and remains usable without memory. Ordinary startup performs no migration, deletion, or process termination.
|
|
272
286
|
|
|
273
287
|
Engram 3.3.2 does not expose `/compatibility`, so reinstalling that version cannot authorize reuse of an existing global store. [Engram 3.4.0](https://github.com/Gentleman-Programming/engram/releases/tag/v3.4.0) includes the endpoint from PR #1792. Back up the existing store before updating its server through its own installation method, then restart that server and Shell. Updating Shell's bundled binary does not replace an already-running global server. Reuse still requires a valid ready response, not just the version number; a token-protected server cannot provide it to Shell's unauthenticated probe. Do not disable authentication to bypass this policy or use an unpublished build.
|
|
274
288
|
|
|
275
|
-
The memory decision never skips or fails setup: `gentle-shell setup` always publishes the verified core, runs Gentle AI and pins the companion, as before. Gentle AI 4.0.0 `install --agent pi` runs no `engram setup` for Pi, and `pi-engram init` only edits settings, so neither opens a store. Setup reclassifies after publishing the core, and the decision only selects the Engram environment its children and the launched Pi receive. On a new machine the wizard publishes the runtime without Engram, so the first `gentle-shell setup` publishes the core and the following launch
|
|
276
|
-
|
|
277
|
-
#### Session-owned local servers
|
|
278
|
-
|
|
279
|
-
An admitted local store now starts only through a private session-owned server. Before provisioning a fresh identity, Shell requires both `engram.sessionOwned: 1` in every selected companion's package metadata (including mixed local/npm selections) and `serve --session-owned` in the verified core's config-free help, checked with an isolated temporary home. It then selects `ENGRAM_SERVER_MODE=session-owned`, without URL, port or socket overrides. The companion must validate the actual `engram-session-owned-v1` readiness record, authenticate every HTTP route, and retain its child's stdin pipe. Pi exit or parent death closes that pipe; EOF cancels startup-lock waits and drains a started server. Reload releases transport without ending the conversation; multiple hosted roots release the child only after the last owner exits.
|
|
280
|
-
|
|
281
|
-
**Release dependency:** the currently pinned core 3.4.0 and companion 0.4.2 do not establish these capabilities. Local memory therefore remains disabled with explicit supporting-release guidance; Shell does not silently launch an old detached daemon. These source changes must not be presented as a working deployed fix until supporting published pins are available. No release version or checksum is invented here.
|
|
282
|
-
|
|
283
|
-
Already verified running shared servers remain explicit URL reuse, never session-owned processes; Shell does not terminate them. Explicit bin, URL, port, socket or data selections are preserved and never probed. An explicit empty, whitespace or conflicting server mode disables local memory rather than overriding the selection; unset it or select exactly `session-owned`. Explicit owned mode cannot be combined with shared URL reuse; unset it when using an already running shared service. Non-bundled installations retain their existing shared default unless they opt in to session-owned mode.
|
|
289
|
+
The memory decision never skips or fails setup: `gentle-shell setup` always publishes the verified core, runs Gentle AI and pins the companion, as before. Gentle AI 4.0.0 `install --agent pi` runs no `engram setup` for Pi, and `pi-engram init` only edits settings, so neither opens a store. Setup reclassifies after publishing the core, and the decision only selects the Engram environment its children and the launched Pi receive. On a new machine the wizard publishes the runtime without Engram, so the first `gentle-shell setup` publishes the core and the following launch starts the shared server. Setup and every launch pin `npm:gentle-engram@0.4.2` through Pi's own `install` command (configuration only) and verify the declaration plus `engram.startupPolicy: 1`; a failed check is reported and Shell still starts, protected by the guard. `setup --dry-run` installs nothing.
|
|
284
290
|
|
|
285
291
|
#### Explicit recovery after a core upgrade
|
|
286
292
|
|
|
287
|
-
|
|
293
|
+
Earlier Shell releases provisioned `~/.engram` themselves and recorded `<prefix>/config/engram-provenance.json`; ordinary startup no longer reads that record. To migrate such a **Shell-provisioned store** with the bundled core explicitly, stop every Engram client and server using the directory, retain a complete backup (including WAL and configuration), then run:
|
|
288
294
|
|
|
289
295
|
```sh
|
|
290
296
|
gentle-shell memory migrate --confirm-quiescent
|
|
291
297
|
```
|
|
292
298
|
|
|
293
|
-
**Release dependency:** this requires a published bundled core advertising `migrate-copy`. The
|
|
299
|
+
**Release dependency:** this requires a published bundled core advertising `migrate-copy`. The pinned Engram 3.5.2 implements it; Engram 3.4.0 did not. Shell checks help in an isolated home and refuses without invoking an unknown migration command or changing the source/provenance. Do not substitute an unpublished binary, edit hashes, or assume equal schema versions authorize recovery.
|
|
294
300
|
|
|
295
301
|
When supported, the provider copies the complete directory to a new sibling and validates/migrates only that copy. Shell checks the provider's directory and identity evidence, renames the original to the reported `backup_dir`, promotes the copy, and atomically replaces its core-bound provenance. Success prints one JSON record with `status: "migrated"`, `instance_id`, and `backup_dir`. Keep that backup until you have verified your records in Shell. Provider failures preserve the original and provenance; any incomplete copy is identified and retained, never promoted. Explicit foreign data locations or endpoints are not adopted by this command.
|
|
296
302
|
|
|
@@ -298,17 +304,16 @@ The confirmation is an operator assertion, not a process lock: source hashes det
|
|
|
298
304
|
|
|
299
305
|
#### Recovering an interrupted migration
|
|
300
306
|
|
|
301
|
-
A marker at `<prefix>/config/engram-migration.json` blocks memory before probes or
|
|
307
|
+
A marker at `<prefix>/config/engram-migration.json` blocks memory before probes or starting a server. It records the `source`, `output`, `backup` paths and `originalProvenance`. **Keep clients stopped and do not simply remove this marker.** Preserve all paths while inspecting them.
|
|
302
308
|
|
|
303
309
|
To roll back an interrupted promotion, first verify the paths and recorded instance identity. If `backup` exists, it is the original directory: retain any current `source` under a separate quarantine name, then restore `backup` to `source`. If no backup exists, do not replace the original source with the incomplete output. Restore `originalProvenance` atomically to `<prefix>/config/engram-provenance.json`, preserving the old core hash exactly. Only after source identity and provenance are reconciled may the marker be removed. Retain the migration output for diagnosis. If these facts cannot be established, leave the marker and request recovery assistance rather than guessing.
|
|
304
310
|
|
|
305
|
-
|
|
311
|
+
No automatic retry, store deletion, or server termination is performed.
|
|
306
312
|
|
|
307
313
|
#### Known limits
|
|
308
314
|
|
|
309
|
-
- **Shared-store residuals.**
|
|
310
|
-
- **
|
|
311
|
-
- **Failed provisioning.** If the identity was created but the record could not be written, later launches see an unrecorded store and keep memory disabled; the notice explains how to recover.
|
|
315
|
+
- **Shared-store residuals.** The header tripwire only sees a newer schema recorded in `engram.db`'s header. A different Engram that changed the store without raising `user_version`, or changes still only in the WAL, are not detected without reading the database; the server that opens the store owns its migrations.
|
|
316
|
+
- **A detached server keeps running.** The server Shell starts is not tied to Pi's lifetime, by design (it is shared). Stop it like any Engram server when you no longer want it; Shell starts it again on the next launch if nothing listens.
|
|
312
317
|
- **Older or other integrations.** gentle-engram versions before 0.4.1, and integrations that do not reach data through `ENGRAM_BIN` (for example an MCP launcher running `engram` from `PATH`), are not covered by the guard.
|
|
313
318
|
- **Non-bundled installs** keep their previous behavior.
|
|
314
319
|
|
|
@@ -319,7 +324,7 @@ S9. Everything Gentle AI and gentle-pi keep lives in the prefix, except Engram's
|
|
|
319
324
|
| Process | Gets |
|
|
320
325
|
|---|---|
|
|
321
326
|
| `gentle-shell setup` (the pinned `gentle-ai install --agent pi`) | `GENTLE_AI_HOME=<prefix>/gentle-ai`, `GENTLE_AI_PI_CONFIG_DIR=<prefix>/config/gentle-ai`, `GENTLE_AI_ENGRAM_BIN=<prefix>/runtime/engram-<v>/engram`, `GENTLE_AI_NO_SELF_UPDATE=1` and `GENTLE_PI_CONFIG_HOME=<prefix>/config`. |
|
|
322
|
-
| Pi and its subagents | `GENTLE_SHELL_PREFIX=<prefix>` and the memory startup policy;
|
|
327
|
+
| Pi and its subagents | `GENTLE_SHELL_PREFIX=<prefix>` and the memory startup policy; `ENGRAM_BIN` is the Shell guard, plus `ENGRAM_URL=http://127.0.0.1:7437` when the shared server is verified. An explicit `ENGRAM_BIN` or `ENGRAM_URL` is kept as is ([Engram startup safety](#engram-startup-safety)). No `GENTLE_AI_*` variable, and `GENTLE_PI_CONFIG_HOME` is left as the user has it. |
|
|
323
328
|
| gentle-pi's own `gentle-ai` runs (review, telemetry trigger, runtime metrics) | The same five variables as setup. |
|
|
324
329
|
| The agent's shell | Pi's environment: the user's own plus the Pi row above. |
|
|
325
330
|
|
|
@@ -329,10 +334,10 @@ S9. Everything Gentle AI and gentle-pi keep lives in the prefix, except Engram's
|
|
|
329
334
|
- **Aligned with Gentle AI 4.0.0.** Gentle AI 4.0.0 reads `GENTLE_PI_CONFIG_HOME` as the parent of its own `gentle-ai` folder: `piBackgroundPolicyPath` in `internal/cli/pi_background.go` writes `<GENTLE_PI_CONFIG_HOME>/gentle-ai/background-subagents.json`, else `~/.pi/gentle-ai/...`. So the config home is `<prefix>/config/gentle-ai`, and only the Gentle AI processes Gentle Shell starts also get `GENTLE_PI_CONFIG_HOME=<prefix>/config`. The policy 4.0.0 writes during setup then lands in the bundled config home, and a release with gentle-ai#5462 writes the same folder through `GENTLE_AI_PI_CONFIG_DIR`. In 4.0.0 only `install`, `sync` and their dry runs read it (the background-policy projection); review and telemetry runs do not, and get it only so every Gentle AI process Gentle Shell starts agrees.
|
|
330
335
|
- **Gentle AI's variables never reach Pi.** Pi's bash tool would pass them to a `gentle-ai` the user runs in the agent's shell, and that run would then use the prefix. Instead, `gentleAiIsolationEnv` (`lib/gentle-ai-binary.ts`) adds them to each `gentle-ai` that a bundled gentle-pi starts itself (the central `gentleAiProcessEnvironment`, the review relay, the runtime metrics send and the telemetry trigger), and the launcher adds them to setup. `GENTLE_AI_ENGRAM_BIN` is set only when our Engram is published.
|
|
331
336
|
- **Engram.** `ensureEngram` (`scripts/bundled-install.mjs`) publishes the pinned Engram release under `runtime/engram-<v>/`. The archive is checked against its pinned size and sha256 from the release's `checksums.txt`. Only the `engram` (or `engram.exe`) regular file is written. `engram version` must print `engram <v>` from the staging folder before the folder is published. `ensureRuntime({ engram: true })` includes it. `gentle-shell setup` in a bundled install ensures it before it runs Gentle AI, and stops if it cannot, whatever the memory decision ([Engram startup safety](#engram-startup-safety)). `gentle-shell upgrade` and `--rollback` pass `engram: true` to the release's own `ensureRuntime`. With `GENTLE_AI_ENGRAM_BIN`, Gentle AI uses that binary as is: no brew, download, `go install`, `PATH` or registry change, and no `go` or `brew` dependency probes.
|
|
332
|
-
- **gentle-engram.** The gentle-engram Pi extension finds Engram only through `ENGRAM_BIN`, read once when it loads, and otherwise runs `engram` from `PATH`. So Pi gets `ENGRAM_BIN` (the
|
|
337
|
+
- **gentle-engram.** The gentle-engram Pi extension finds Engram only through `ENGRAM_BIN`, read once when it loads, and otherwise runs `engram` from `PATH`. So Pi gets `ENGRAM_BIN` (the guard; memory reaches the shared server through `ENGRAM_URL`), and no `PATH` entry is added. An `ENGRAM_BIN` the user set is kept. The agent's shell inherits `ENGRAM_BIN` too, so an Engram MCP launcher started there through `ENGRAM_BIN` uses the same guard.
|
|
333
338
|
- **Personas.** Setup snapshots and restores the persona Gentle AI may rewrite: the prefix's `config/gentle-ai/persona.json`, and also the user's `~/.pi/gentle-ai/persona.json`. A Gentle AI release without the variables still writes the user's file, and restoring an unchanged file does nothing. The managed-asset record is restored only in the user's `~/.gentle-ai/state.json`; the prefix's record belongs to the pinned Gentle AI.
|
|
334
339
|
- **pi-pretty and prompt history.** In bundled mode only, the pi-pretty wrapper passes `deps.sdk` with Pi's five tool factories and `getAgentDir`, so its FFF database lands in `<agent home>/pi-pretty/fff`, and prompt history keeps its store under `<agent home>/history` ([Prompt history](prompt-history.md)). Elsewhere both keep their existing locations: Pi's deps reach pi-pretty unchanged (`$HOME/.pi/agent/pi-pretty/fff`, or no store without `HOME`), and history stays under `~/.pi/agent/history`, also in the isolated home of a pnpm or npm install, so existing histories are not left behind.
|
|
335
|
-
- **Effective with a later Gentle AI.** gentle-pi pins Gentle AI 4.
|
|
340
|
+
- **Effective with a later Gentle AI.** gentle-pi pins Gentle AI 4.3.1 today (`INSTALLER_VERSION`); the following are historical compatibility notes for Gentle AI 4.0.0, which ignores the four `GENTLE_AI_*` variables. Whether 4.3.1 includes gentle-ai#5462 is unverified here. Until gentle-pi pins a Gentle AI release that contains gentle-ai#5462:
|
|
336
341
|
- Setup still writes `~/.gentle-ai` and `~/.pi/gentle-ai`, with the restores above, and still acquires Engram its own way.
|
|
337
342
|
- The persona goes to the user's `~/.pi/gentle-ai/persona.json` (Gentle AI 4.0.0 resolves it from the OS home) and is restored there. The prefix's `config/gentle-ai/persona.json` is not created by setup.
|
|
338
343
|
- The background-subagents policy already lands in `<prefix>/config/gentle-ai/` through `GENTLE_PI_CONFIG_HOME=<prefix>/config` (see above).
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
How the Gentle Pi orchestrator decides who verifies a bounded writer's work. The always-on parent prompt renders a `Receipt-driven development: on|off|unknown` line; the verification module (`assets/orchestrator-verification.md`, Verification rule) keys the verification rule on it. Because the line sits in the cached system-prompt prefix, a session keeps the first line it rendered and re-renders it only when RDD turns off or back on (which also drops or restores the review execution contract); an `unknown` to `on` flip or a deciding-source change keeps the original text, and review tools always read the live mode. While the pinned line reads `off`, the parent request also carries a lean review loadout: `gentle_review` keeps its schema but its snippet, guidelines, and description cover only `assess`, and the `gentle_review_capture`, `gentle_review_capture_group`, and `gentle_review_scope` declarations are hidden (they stay registered and active). The loadout follows the pinned line, so it changes only at the next run after RDD turns off or back on, together with the review execution contract; `on` and `unknown` keep the full registered text. This page is package-owned; `docs/review-integration.md` mirrors the Gentle AI contract and must stay byte-identical to it.
|
|
4
4
|
|
|
5
|
+
## Background capability admission
|
|
6
|
+
|
|
7
|
+
An explicit agent `tools` declaration containing `bash_background` requires the background-subagents policy to resolve to `on` at dispatch, for both task and background launches. Otherwise the runner fails the task before spawn and reports the policy file, opt-in schema, and `/gentle:background-subagents enable|disable|status`. Fix the deciding policy explicitly; automation must not toggle it. Passing admission does not promise child background-tool support (future Slices 2–3); ordinary missing-tool reporting remains the backstop. See the [policy contract](readme-reference.md#capability-reference).
|
|
8
|
+
|
|
5
9
|
## Receipt-driven development on
|
|
6
10
|
|
|
7
11
|
Verification is the same with RDD on, off, or unknown (verify-always-rdd-high S1). The bounded writer runs the exact commands the parent lists under `## Verification`, in the foreground, and reports each as `<command>: <observed result>`; after it returns, the parent calls `assess` and follows the risk tier below. The native review is an additional outside view of the change: it never replaces or skips the tier's verification, and the tier's verifier runs before review. A declined consent, a clone-local disable, or a refused START/STATUS therefore changes nothing about verification.
|
|
@@ -44,6 +48,8 @@ The `gentle_review` tool's `assess` operation (`extensions/gentle-ai.ts`) combin
|
|
|
44
48
|
|
|
45
49
|
The plan risk (`risk`) is high only with an escalation; otherwise a native passive stays passive and every other native tier is medium. The native tier stays visible as `nativeRisk`. The independent verifier is for concrete occasions: the plan adds it only when `escalate` names a Task Size high-risk item, never for size, a native tier alone, a failed assessment, or the model or effort that wrote the change.
|
|
46
50
|
|
|
51
|
+
With RDD off, ASSESS remains read-only even when native reports `reviewDue` or a continuation: relay those fields unchanged, but do not execute the continuation, invoke STATUS or another review lifecycle operation, or enable RDD based on assessment metadata. Continue the verification plan and applicable functional checks; the named-risk independent verifier remains required.
|
|
52
|
+
|
|
47
53
|
This table applies in every RDD state; a closed native review never removes a verifier the tier requires. An unknown RDD line never lowers a tier below `off`. The parent's own spot check (re-running one reported command before delivery) stays required in every tier.
|
|
48
54
|
|
|
49
55
|
A native code review is not a substitute for applicable functional checks: tests, builds, and functional verification such as browser checks for UI changes still run when applicable. Review outcomes never authorize delivery; human consent for native review and the user-owned RDD switch are unchanged.
|
|
@@ -49,7 +49,11 @@ Aliases are display hints, never authentication or routing identities.
|
|
|
49
49
|
|
|
50
50
|
Aliases are optional envelope metadata in the existing branch-local state record,
|
|
51
51
|
restored with `getBranch()` on start/reload/tree navigation. State replacement or
|
|
52
|
-
withdrawal preserves them; no subject preserves both.
|
|
52
|
+
withdrawal preserves them; no subject preserves both. When a publication includes
|
|
53
|
+
`state.work` with an explicit `topic` and no `subject`, the topic refreshes Current
|
|
54
|
+
(the first such classification also sets Initial on a new record); an explicit
|
|
55
|
+
`subject` in the same publication wins, and state-only refreshes never re-derive
|
|
56
|
+
the alias from previously stored work. Subject-only declarations
|
|
53
57
|
preserve state contents, recorded cwd and `recordedAt`: old progress is not a fresh
|
|
54
58
|
status update. Publish subject and state together when changing work. New records
|
|
55
59
|
use null/null until the first declaration; legacy records without aliases keep
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Gentle Music
|
|
2
|
+
|
|
3
|
+
`/gentle:music` plays [gentle-stream](https://github.com/Gentleman-Programming/gentle-stream) music from inside Gentle Shell.
|
|
4
|
+
|
|
5
|
+
## Open the player
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
/gentle:music
|
|
9
|
+
/gentle:music rainy lo-fi night
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The command hands the whole terminal to gentle-stream's own TUI, the same way Pi's external editor (`ctrl+g`) does. Any text after the command is passed as the mood (`--mood`), and the session's current model is passed as `--model provider/id`, so gentle-stream interprets the mood with the model you already use.
|
|
13
|
+
|
|
14
|
+
Leave the player with:
|
|
15
|
+
|
|
16
|
+
| Key | Result |
|
|
17
|
+
| :-- | :-- |
|
|
18
|
+
| `b` | Back to Pi; the music keeps playing. |
|
|
19
|
+
| `q` | Back to Pi; the music stops. |
|
|
20
|
+
|
|
21
|
+
Pi returns exactly as it was: the draft, the transcript, and the layout are redrawn. While the player is open, `ctrl+c` goes to gentle-stream, not to Pi. If gentle-stream exits with an error, Pi shows a short notice.
|
|
22
|
+
|
|
23
|
+
Opening `/gentle:music` again while music plays attaches to the same music.
|
|
24
|
+
|
|
25
|
+
## Control the music without leaving Pi
|
|
26
|
+
|
|
27
|
+
A single control word runs `gentle-stream ctl …` in the background and shows the result as a notice. The terminal stays with Pi.
|
|
28
|
+
|
|
29
|
+
| Command | Result |
|
|
30
|
+
| :-- | :-- |
|
|
31
|
+
| `/gentle:music next` | Next track. |
|
|
32
|
+
| `/gentle:music pause` | Pause. |
|
|
33
|
+
| `/gentle:music play` | Resume. |
|
|
34
|
+
| `/gentle:music stop` | Stop the music. |
|
|
35
|
+
| `/gentle:music status` | One line, for example `♪ Neon Rain · synthwave · playing`, or `nothing is playing`. |
|
|
36
|
+
|
|
37
|
+
Only an exact single word is a control word. `/gentle:music next to the sea` opens the player with the mood `next to the sea`.
|
|
38
|
+
|
|
39
|
+
## Stopping on exit
|
|
40
|
+
|
|
41
|
+
When you quit Pi after using `/gentle:music`, Gentle Shell runs `gentle-stream ctl stop` so no music outlives the shell. It waits at most about 2 seconds. Starting a new session, resuming, forking, or reloading keeps the music playing.
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
Gentle Shell looks for gentle-stream in this order:
|
|
46
|
+
|
|
47
|
+
1. `gentle-stream` on `PATH`.
|
|
48
|
+
2. `uvx`, running gentle-stream straight from its repository (the first run downloads it).
|
|
49
|
+
3. `uv`, through `uv tool run`.
|
|
50
|
+
|
|
51
|
+
With none of them, `/gentle:music` explains how to install and does nothing else. Install [uv](https://docs.astral.sh/uv/getting-started/installation/), or install gentle-stream permanently:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
uv tool install 'gentle-stream[samples] @ git+https://github.com/Gentleman-Programming/gentle-stream'
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Limits
|
|
58
|
+
|
|
59
|
+
- The player needs the interactive terminal. In RPC, JSON, and print modes, `/gentle:music` shows a notice and does nothing.
|
|
60
|
+
- There is no default shortcut.
|
|
61
|
+
- gentle-stream starts its own `gentle-shell` process to interpret moods; Gentle Shell does not pass its own launcher path.
|
package/docs/gentle-shell.md
CHANGED
|
@@ -8,10 +8,19 @@ Source map: [shell extension](../extensions/gentle-shell.ts), [shell bar](../lib
|
|
|
8
8
|
|
|
9
9
|
## Updating Pi safely
|
|
10
10
|
|
|
11
|
-
Run `gentle-shell update` to update the Pi this launcher runs. It also works when that Pi is older than the required minimum version, which every other command refuses. Shell verifies npm/pnpm global listing JSON and canonical package roots before installing exactly one supplying package. This supports pnpm v11 linked stores without relying on `PNPM_HOME` containment. When the launcher runs its adjacent Pi peer, the supplier is the listed `gentle-pi` package itself: Shell is reinstalled at its current version so the package manager re-resolves the peer, because updating a separate global Pi never changes the peer a Shell install runs. A Pi found on `PATH` or through `GENTLE_SHELL_PI` is updated through its own listed global package; a package-manager shim is followed to the single `cli.js` it names. Pi and Shell are never combined into a comma install.
|
|
11
|
+
Run `gentle-shell update` to update the Pi this launcher runs. It also works when that Pi is older than the required minimum version, which every other command refuses. Shell verifies npm/pnpm global listing JSON and canonical package roots before installing exactly one supplying package. This supports pnpm v11 linked stores without relying on `PNPM_HOME` containment. When the launcher runs its adjacent Pi peer, the supplier is the listed `gentle-pi` package itself: Shell is reinstalled at its current version so the package manager re-resolves the peer, because updating a separate global Pi never changes the peer a Shell install runs. A main-channel Shell (`<version>-main.<sha12>`) is never published, so it is reinstalled 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); when that tarball is missing, `update` installs nothing and names the rebuild path (`gentle-shell upgrade --channel release`, then `--channel main`), because `upgrade --channel main` alone is a no-op when already at the latest main. A Pi found on `PATH` or through `GENTLE_SHELL_PI` is updated through its own listed global package; a package-manager shim is followed to the single `cli.js` it names. Pi and Shell are never combined into a comma install.
|
|
12
12
|
|
|
13
13
|
Unknown or ambiguous ownership, npm source/link packages, and pnpm groups shared with other top-level packages refuse without installation changes. Separate groups in one aggregated listing are allowed. After the install, Shell reads the supplied Pi version back from a fresh listing and reports whether it changed. pnpm installs only releases older than its `minimumReleaseAge` setting (pnpm 11 defaults to 4320 minutes), so a very recent Pi release is picked up once it is old enough; Shell reports that rule instead of overriding it. Package managers run from the system temporary directory so a project's `packageManager` pin never changes which pnpm answers. Use the supplying package manager for source checkouts or unsupported layouts. `gentle-shell update --extensions-only` remains an extension-only Pi command; prefix-bundled Pi still updates with `gentle-shell upgrade`. See [managing packages](readme-reference.md#managing-packages) for the ownership contract.
|
|
14
14
|
|
|
15
|
+
When the install fails, `update` names the package manager and the exact command it ran, then one sanitized line of that manager's own output. That line is the last error line (`Error:` or an `ERR_` code) in its stdout or stderr, stderr's when both have one, because npm prints its error on stderr while pnpm 11 prints `ERR_PNPM_*` on stdout. A warning on stderr never hides that error. Without any error line, it is the last line of stderr, else of stdout. Terminal escapes and control characters are removed, your home directory becomes `~`, and the line is at most 300 characters. For example:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
gentle-shell update: pnpm (/usr/local/bin/pnpm) could not install /Users/you/.pi/gentle-ai/main/packages/gentle-pi-<version>.tgz
|
|
19
|
+
[ERR_PNPM_INVALID_VERSION_UNION] Invalid versions union. Found: "gentle-pi@file:...". Use exact versions only.
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`ERR_PNPM_INVALID_VERSION_UNION` during `update` usually means more than one pnpm is installed: an older pnpm on `PATH` cannot read the `allowBuilds` key a newer pnpm wrote to the global `pnpm-workspace.yaml`. Keep a single standalone pnpm.
|
|
23
|
+
|
|
15
24
|
## v2.6.0 workspace updates
|
|
16
25
|
|
|
17
26
|
The [v2.6.0 release](https://github.com/Gentleman-Programming/gentle-pi/releases/tag/v2.6.0) makes the workspace state more durable and inspectable:
|
|
@@ -21,7 +30,7 @@ The [v2.6.0 release](https://github.com/Gentleman-Programming/gentle-pi/releases
|
|
|
21
30
|
- The Agents List and Details views preserve the orchestrator/session hierarchy and completion, abort, and lost-exit history. Parent-child queries and notifications have an explicit handoff path, while model, effort, and usage stay observable per task.
|
|
22
31
|
- Named `/gentle:profiles` atomically route the orchestrator separately from packaged and review roles; see the [technical reference](readme-reference.md#agent-model-profiles) for the profile model.
|
|
23
32
|
|
|
24
|
-
The source checkout prepares `gentle-pi` `4.0.0` with a package-local Gentle AI `v4.
|
|
33
|
+
The source checkout prepares `gentle-pi` `4.0.0` with a package-local Gentle AI `v4.3.1` pin; this does not imply that the package release has been published.
|
|
25
34
|
|
|
26
35
|
## Shell interactions and runtime behavior
|
|
27
36
|
|
|
@@ -36,12 +45,12 @@ At 140 columns or wider, fullscreen defaults to a live header over a transcript-
|
|
|
36
45
|
```
|
|
37
46
|
|
|
38
47
|
- The header carries live session data: session identity on the left (brand, cwd, branch, dirty count, model · effort · profile) and the two live counters right-aligned (the context gauge and session cost). The effort reads `auto` for NaN models that manage their reasoning depth themselves (DeepSeek V4 Flash, Qwen 3.8 Flash, MiMo), with a one-time notice explaining that the selected level does not change the depth. It never shows the working/thinking state or extension statuses — those stay in the prompt indicator and the Status surface. When the terminal is too narrow for everything, segments give way in a fixed order — profile, then effort, then the whole cwd/branch/dirty group — before the counters are touched; below that, only the brand survives, and below that the header renders nothing.
|
|
39
|
-
- The right rail scrolls **Status → Changes → TODO**. Cards cache their rendered content until their own digest or an explicit invalidation changes. `neon` keeps the rounded border and accent title; `float` uses a tone background, a full-height `▎` accent, one-column transparent margins, painted padding above and below, and a blank painted separator between heading and body. Warning/error/success panels retain their tone colors.
|
|
48
|
+
- The right rail scrolls **Status → Changes → Agents → TODO**. Cards cache their rendered content until their own digest or an explicit invalidation changes. `neon` keeps the rounded border and accent title; `float` uses a tone background, a full-height `▎` accent, one-column transparent margins, painted padding above and below, and a blank painted separator between heading and body. Warning/error/success panels retain their tone colors.
|
|
40
49
|
- The Status card carries Project (cwd, branch, session name, active profile), Changes, and Integrations (other extensions' statuses); its live digest detects changes without requiring an event. Model, effort, context, cost, and the per-model usage table live in the header instead — the header ticks every frame, so duplicating them in a card would just make that card repaint every frame too.
|
|
41
|
-
- Gentle Agents is
|
|
50
|
+
- Gentle Agents follows TODO: while the fullscreen rail is showing, the Agents card moves into it and lists every shown task; without the rail (narrow fullscreen or regular mode) it stays above the editor. Its card has fixed right-aligned columns for `model · effort`, tokens, cost, and elapsed, each sized to the widest value among the shown tasks — so the numbers line up vertically even when one row's values are much shorter than another's. A queued task fills only the elapsed column with the word `queued`, leaving the other columns blank rather than overwriting the row.
|
|
42
51
|
- The sidebar reuses its last frame until something it paints changes, so silent frames stay cheap; a per-section cache means one card's changing digest (or the header's) never forces an unrelated card to redraw.
|
|
43
52
|
- Header placement is configurable. Above input, the float header has a full-width background, painted padding above and below its content, and a transparent `▔` bottom edge. Below input, the float footer groups Changes (when the session's roots have uncommitted work), header data, and locally owned integration statuses under one upper edge; it never duplicates statuses owned by the rail.
|
|
44
|
-
- Below 140 columns, fullscreen has no sidebar. A configured top header owns the narrow status surface; otherwise the bottom bar owns it, unless Status is hidden. Regular mode keeps the compact one-line bottom bar and the above-editor Agents widget, without a fullscreen header or sidebar.
|
|
53
|
+
- Below 140 columns, fullscreen has no sidebar. A configured top header owns the narrow status surface; otherwise the bottom bar owns it, unless Status is hidden. The Agents and TODO cards then return above the editor. Regular mode keeps the compact one-line bottom bar and the above-editor Agents widget, without a fullscreen header or sidebar.
|
|
45
54
|
|
|
46
55
|
The regular-mode compact bar replaces pi's three-line footer with a single line of segments:
|
|
47
56
|
|
|
@@ -66,8 +75,32 @@ The prompt follows the selected card style. `neon` keeps pi's editor in its roun
|
|
|
66
75
|
- The petal is still with a `waiting for input` label in float while pi waits, spins with a `working` label while the agent works, and turns amber with a `queued` label when messages are waiting behind the current turn. In float it lives inside the painted top row; in neon it lives in the top rule. Pi's own "Working" row above the editor is hidden.
|
|
67
76
|
- The empty-editor typing hint appears only while the editor is empty; Esc/queued hints remain inside the painted top row even with a nonempty float draft. Widths below 10 columns or a missing/unusable background keep the complete neon prompt path.
|
|
68
77
|
- With Vim editing off, the prompt selects text natively: `shift+home` / `shift+end` select to the line edge and `alt+e` selects the whole draft; backspace, delete, a printable key or a paste replaces the selection in one undoable edit. `alt+a` also selects all, but only when no extension shortcut claims it: by default it opens Gentle Agents. A registered extension shortcut always wins over these selection keys.
|
|
78
|
+
- Pi's paste-image key (`app.clipboard.pasteImage`: `ctrl+v`, or `alt+v` on Windows) turns a clipboard image into an `[Image#N]` chip instead of a temp-file path. One Backspace or Delete removes the whole chip; cursor and word motions, word deletion, wrapping and Vim NORMAL treat it as one unit. On submit, every chip still in the draft is sent as a real image attachment, so the model sees it without calling `read`. A deleted chip is never sent. The bytes stay in memory; no temp file is written. See [Pasted images](#pasted-images).
|
|
69
79
|
- If another extension already installed a custom editor, Gentle Shell leaves it alone.
|
|
70
80
|
|
|
81
|
+
### Pasted images
|
|
82
|
+
|
|
83
|
+
While a draft holds chips, a strip above the prompt lists each one:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
[Image#1] png · 1280×720 · 84 KB
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- **Preview:** terminals with an image protocol (Kitty, Ghostty, WezTerm, Warp, iTerm2) draw a small thumbnail under each label while the agent is idle. While it works, and in terminals or multiplexers that hide the protocol (such as tmux), the label alone is shown, so streaming never re-sends the image to the terminal.
|
|
90
|
+
- **Clipboard sources:** the native clipboard on macOS and Windows; `wl-paste` or `xclip` on Linux. On WSL, a Windows screenshot (`Win+Shift+S`) is read from the Windows clipboard through `powershell.exe`, because the Linux clipboard never receives it.
|
|
91
|
+
- **What stays Pi's:** files copied in a file manager, text, and image formats other than PNG, JPEG, WebP and GIF go through Pi's own paste handler unchanged.
|
|
92
|
+
- **Models without image input:** the strip warns before you send. If you send anyway, each chip becomes `[Image#N omitted: the current model does not accept images]` and a notice explains why, so nothing is dropped silently.
|
|
93
|
+
- **Numbering:** numbers keep counting up for the whole session, so a chip recalled from prompt history never points at a newer image. A recalled chip is plain text; paste the image again to attach it.
|
|
94
|
+
- **Sending while the clipboard is read:** reading the Windows clipboard on WSL takes about a second. If you send the message before it finishes, the image is discarded with a notice instead of landing in the next draft; paste again to attach it.
|
|
95
|
+
- **Vim NORMAL:** the paste key enters INSERT and pastes the chip. NORMAL motions step over a chip as one unit; an operator whose range covers a chip removes it whole.
|
|
96
|
+
- **Terminals that capture the paste key:** some terminals keep `ctrl+v` for their own paste, and nothing reaches Pi when the clipboard holds only an image (Warp on Windows does this). Bind a second key in `~/.pi/agent/keybindings.json`, then restart:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{ "app.clipboard.pasteImage": ["ctrl+v", "alt+v"] }
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Changes
|
|
103
|
+
|
|
71
104
|
Changes shows the **current Git state** — working tree against HEAD, untracked files included — of the session's repository and of every worktree or repository its subagents used that still exists. Nothing is scanned at startup; the list fills at the first turn end or when the panel opens, then refreshes at each turn end and while the panel is open. Fullscreen, the sidebar, and mouse interaction are unchanged.
|
|
72
105
|
|
|
73
106
|
```text
|
|
@@ -96,7 +129,7 @@ Captured evidence (`gentle-pi.session-change/v1`) is still stored for session st
|
|
|
96
129
|
- `F` toggles diff-only mode at any width: the file list and its separator hide so the diff uses the full width. There `j`/`k` still move between files (across worktrees; the path row shows which), the scroll keys and the wheel scroll the diff, `o`/Enter and `r` keep working, the first Escape returns to the file list, and `q` closes. Every opening starts with the file list visible.
|
|
97
130
|
- Fullscreen left-click selects files; mouse wheels scroll the file list and diff independently. Hovering an unselected row (worktree or file, in either pane's list) paints it in the same shared hover role every clickable surface in the shell uses; it never opens or selects the file, and never overrides the already-selected row's own role.
|
|
98
131
|
- Opening, pressing `r`, and the overlay's refresh cadence re-read each root's Git status; a same-line-count edit reloads the open diff.
|
|
99
|
-
- On a file, `o` or Enter opens the actual current file in `$VISUAL` or `$EDITOR`, with its worktree as cwd.
|
|
132
|
+
- On a file, `o` or Enter opens the actual current file in `$VISUAL` or `$EDITOR`, with its worktree as cwd. Editor launches pass paths as literal arguments, never through a shell. On Windows, configure a direct executable (for example `notepad.exe`); `.cmd`/`.bat` editor shims are refused. Launch failures appear as warnings after the terminal UI is restored. This also applies when opening an Agents session transcript. Editor commands retain literal-space splitting: quoted executable paths and shell expressions are not supported.
|
|
100
133
|
- `GENTLE_PI_SHELL_CHANGES_KEY` rebinds the shortcut; `off` disables it. `GENTLE_PI_SHELL_CHANGES_POLL_MS` controls how often the open overlay re-reads Git. `GENTLE_PI_SHELL_CHANGES_WATCH_MS` no longer enables filesystem polling.
|
|
101
134
|
- No uncommitted changes in the session's roots means no widget and an informational notice.
|
|
102
135
|
|
|
@@ -255,7 +288,7 @@ In the isolated Gentle Shell home, `settings.json` does not declare gentle-pi; t
|
|
|
255
288
|
- Presence refresh is paged while the overlay is open. Graceful shutdown withdraws an instance; after abrupt closure its last heartbeat may remain visible for up to 15 seconds plus the time to complete the next directory refresh. A recent heartbeat is a heuristic, not proof that a process is alive. Same-profile, same-user processes share retained activity text; this is not an authorization channel.
|
|
256
289
|
- `alt+s` confirms stopping the current active or queued subagents owned by the current process. `GENTLE_PI_AGENTS_STOP_KEY` rebinds it; `off` disables it.
|
|
257
290
|
- Finished tasks are written to `~/.pi/agent/gentle-agents/tasks/` (one JSON per task, newest `history_max_tasks` kept, default 200) and come back on demand for `subagent_result` and `subagent_continue`; an id looked up this way from an unrelated session never enters the overlay or becomes cancellable. Child sessions live under `~/.pi/agent/gentle-agents/sessions/`.
|
|
258
|
-
- `ctrl+shift+a` collapses the card to its first row (`GENTLE_PI_AGENTS_KEY`), `GENTLE_PI_AGENTS_VIEW_KEY` rebinds the overlay, `GENTLE_PI_AGENTS_PI` overrides the pi command used for children, and `GENTLE_PI_AGENTS=0` disables the tools and the card.
|
|
291
|
+
- `ctrl+shift+a` or a left click on the card's `▾ Collapse` / `▸ Expand` header control collapses the card to its first row (`GENTLE_PI_AGENTS_KEY` rebinds the key), `GENTLE_PI_AGENTS_VIEW_KEY` rebinds the overlay, `GENTLE_PI_AGENTS_PI` overrides the pi command used for children, and `GENTLE_PI_AGENTS=0` disables the tools and the card.
|
|
259
292
|
|
|
260
293
|
### Background jobs
|
|
261
294
|
|
|
@@ -329,6 +362,43 @@ Expanded cards reserve at most one third of the terminal height (up to 16 rows,
|
|
|
329
362
|
- Only top-level session files are read: subagent runs are not included, and the panel says so. The first opening scans every file; later openings reread only files that changed.
|
|
330
363
|
- There is no default shortcut. Set `GENTLE_PI_STATS_VIEW_KEY` (for example `alt+t`) to bind one; `off` or empty leaves it unbound.
|
|
331
364
|
|
|
365
|
+
### Gentle Design
|
|
366
|
+
|
|
367
|
+
`/gentle:design <brief>` asks the session model to design the brief with the bundled `gentle-design` skill. It works with any provider: the model writes several clearly different directions (3 by default), each labeled with its tradeoff, as self-contained HTML artboards under `design/<slug>/`, plus a `design.json` manifest. Artboards inline their CSS, JS, and SVG and use system fonts, so they open offline in any browser. When `design/system.md` exists, the skill follows its tokens. Ask for changes to one artboard and only that file changes; "save and try a different approach" adds an artboard and keeps the others.
|
|
368
|
+
|
|
369
|
+
You do not need the command: ask in plain language for a screen, mockup, landing page, or a few visual directions, and the session uses the gentle-design skill by default with any provider. After it writes or changes a design under `design/<slug>/`, the model opens the canvas on it (or refreshes the running one) through the `gentle_design` tool, unless you ask it not to. The same tool lists the designs and their artboards, shows whether the canvas is running and at which URL, stops the canvas, and starts the handoff of an artboard (`<slug>/<artboard>`) to the project's real stack, using exactly the text `/gentle:design implement` sends. Briefs and the design-system sync go through the skill itself. The `/gentle:design` subcommands remain available as optional shortcuts, and they share the same canvas server as the tool. Delegated subagents (`GENTLE_PI_AGENTS_CHILD=1`) do not get the default design flow.
|
|
370
|
+
|
|
371
|
+
The canvas opens in navigation mode: the mouse wheel, trackpad, and drag always pan or zoom the canvas, even over an artboard, and Ctrl/Cmd + wheel zooms. Hovering an artboard shows "Click to use this design"; clicking it enters focus mode, which shows that artboard at its designed width at 100% and lets it own the pointer and keyboard, so its own scrolling, hovers, buttons, and inputs behave like the real page. While an artboard is in focus, the comments panel hides to make room, the rest of the canvas is dimmed and does not pan or zoom, and an artboard taller than the window scrolls inside its frame. To return to navigation mode, press the floating "Back to canvas" button or `Shift+Esc`, which works even while typing inside the artboard; plain `Esc` stays with the design, and the previous zoom, position, and comments panel are restored. Comment mode keeps working in both modes: a click picks an element instead of entering focus mode.
|
|
372
|
+
|
|
373
|
+
- While the agent is busy, the run is queued as a follow-up.
|
|
374
|
+
- `/gentle:design open [slug]` shows a design on a local canvas in the default browser: every artboard side by side at its manifest size, with its title and tradeoff; zoom with the buttons or Ctrl/Cmd + wheel, pan by dragging or scrolling, and Fit to the window. The canvas reloads an artboard when its file changes and the whole design when `design.json` changes. Without a slug it opens the most recent design. The URL is always printed; when the browser cannot be opened, open it manually.
|
|
375
|
+
- `/gentle:design` with no arguments opens the most recent design (by `design.json` modification time) the same way. When the project has no design yet but has `design/system.html`, it and `open` show the canvas with only the system board; with neither, they print usage.
|
|
376
|
+
- Comments: turn on Comment mode, click an element in an artboard, and type a comment. Every comment is saved in `design/<slug>/comments.json` with its artboard, CSS selector, text excerpt, date, and status (`open` or `resolved`), so any agent or later session can read it.
|
|
377
|
+
- **Send now** (the default) also sends the session one message with the design, the comment id, the artboard file, the selector, the excerpt, and the comment; while the agent is busy, it is queued as a follow-up.
|
|
378
|
+
- A comment can carry one screenshot, useful for what only shows between states, such as an animation or a transition: paste an image into the comment popover, drop one onto it, or use **Attach screenshot** (PNG, JPEG, WebP, or GIF, up to 5 MB). It is saved as `design/<slug>/.screenshots/<id>.<ext>`, named in the comment's optional `screenshot` field, shown as a thumbnail in the Comments panel, and reaches the session as an image attached to the comment message (a Send all message attaches at most 6; the rest are named for the read tool).
|
|
379
|
+
- **Collect** only saves the comment. **Send all (N)** then sends every open, unsent comment as one message. The canvas remembers the mode while the canvas server runs.
|
|
380
|
+
- A numbered pin marks each commented element and follows zoom and pan. The Comments panel lists open and resolved comments; selecting one highlights its pin and scrolls the canvas to it, and each comment can be resolved or reopened there. A comment whose element no longer exists shows as **Detached**.
|
|
381
|
+
- The agent applies a comment by editing only that artboard, then marks it resolved with the `gentle_design_comments` tool (`list` and `resolve`), or by editing `comments.json` when it has no tool. The canvas updates live when the file changes, whoever wrote it. Pi's `sendUserMessage` is fire-and-forget, so the canvas reports a delivery as failed (the comment stays saved and unsent) only when sending throws synchronously; a failure later inside the session is not visible to the canvas.
|
|
382
|
+
- `/gentle:design stop` closes the canvas; quitting or replacing the session closes it too. There is one canvas server per session, and a second `open` reuses it.
|
|
383
|
+
- `open` reuses the canvas tab that is already open: while a canvas page is connected, the command and the `gentle_design` tool tell that page to show the requested design and reload it from disk (keeping zoom, pan, and focus mode when it is the same design), and report "Design canvas refreshed" with the URL. The browser opens a new tab only when no canvas page is connected, for example after you closed it or when the server had to start.
|
|
384
|
+
- `/gentle:design sync` (it takes no arguments; extra words warn and send nothing) asks the session model to capture the project's design system with the same skill (queued as a follow-up while the agent is busy). It reads, and never edits, the project's design sources: CSS custom properties (`:root`, `@theme`, `[data-theme]`), the Tailwind config or v4 `@theme`, component library folders, existing token files, and fonts. It writes two files:
|
|
385
|
+
- `design/system.md`: colors (token, value, usage), typography, spacing, radius, shadows, and component rules, each with the path it came from. Later design runs use only these tokens, and the skill checks every finished artboard's colors and fonts against them and fixes any deviation.
|
|
386
|
+
- `design/system.html`: a self-contained 1440 px artboard that renders those tokens and the core components.
|
|
387
|
+
|
|
388
|
+
When the project has no design sources, the model says so and proposes a minimal starter system instead of inventing project tokens.
|
|
389
|
+
|
|
390
|
+
You rarely need to run `sync` yourself. Before a new design, the skill calls the `gentle_design` tool's `list` action, which reports the project's design sources (the first 20 paths and a total) and the state of `design/system.md`. When the project has design sources but no `design/system.md`, the model syncs first, says so in one line, and then designs with those tokens. When the project has no design sources, it designs freely. When a source changed after `design/system.md` was written (by modification time), the model names it, says the tokens may be outdated, and offers to sync again; it re-syncs only with your OK. A design source is a `tailwind.config.{js,cjs,mjs,ts}`; a `.css`, `.scss`, or `.pcss` file that uses `@theme` or declares a custom property in a `:root` or `[data-theme]` rule; a `.json`, `.js`, `.ts`, or `.css` file whose name has `tokens` as a whole word (`tokens.json`, `design-tokens.ts`, `theme.tokens.css`; never `token.ts`, `refreshToken.ts`, `tokenizer.ts`, or a `.test`/`.spec` file); or a `theme.js`/`theme.ts` that exports a `colors` key. The detection walk skips `node_modules`, `dist`, `build`, `out`, `coverage`, every dot-directory (such as `.git`, `.next`, `.worktrees`), and the project's own `design/` folder; it does not follow symlinks, goes at most 6 directories deep, stops after 5000 files, and reads at most 256 KiB of each file.
|
|
391
|
+
- When `design/system.html` exists, the canvas shows it as the first board of every design, labeled **Design system** with "Project tokens (design/system.md)", and reloads it when the file changes. Comment mode does not apply to that board (its tooltip says so): change the system by updating the design sources and running `sync` again.
|
|
392
|
+
- `/gentle:design implement <slug>/<artboard>`, or **Implement this** on an artboard's header in the canvas (after a confirm step; never on the system board), sends the session one handoff message, queued as a follow-up while the agent is busy. Both send the same text: the artboard path, title, and tradeoff; an instruction to build it in the project's real stack with the artboard as the visual spec, mapped to existing components rather than copied; `design/system.md` as the token source when it exists; and every open comment on that artboard, to apply and then resolve with `gentle_design_comments`. An unknown design or artboard warns with the valid `<slug>/<artboard>` values and sends nothing. An invalid `feature` link in `design.json` is reported as a warning, and the handoff goes out unlinked. The handoff itself commits nothing.
|
|
393
|
+
- ODD link: a design that comes from a tracked ODD feature records it in `design.json` as `"feature": "odd/tasks/<feature>.md"`, and the skill appends a Log entry naming the design to that document; small, untracked work has no `feature` and stays standalone. The canvas top bar shows **Feature: <path>** for a linked design, and the handoff asks to track the implementation in that document instead of sizing it from scratch. Only a relative `odd/tasks/<name>.md` path is accepted; any other value is ignored and reported as a warning in the canvas.
|
|
394
|
+
- Handoff state: every handoff (the canvas button, the command, or the tool's `implement`) is recorded in `design/<slug>/handoffs.json` before it is sent, and the handed-off artboard becomes the design's **chosen** direction: its header shows a **Chosen** badge and an accent frame, and the other artboards show **Alternative**. Handing off another artboard moves the mark. After **Send**, a toast confirms it, and the artboard's header shows **Queued** (the agent was busy) or **Implementing…** (it was idle), then **In progress** and **Implemented ✓** as the agent reports them with the `gentle_design` tool's `handoff` action, which the handoff message asks it to call. The canvas updates live, the badge names the linked feature document, and `list` reports each design's chosen artboard and handoff states. When the agent marks an artboard implemented with the `previewUrl` of the running app, **Compare** shows the artboard and the app side by side at the artboard's size, at 100%, with **Scale to fit** when the pair is wider than the window; exit with **Back to canvas** or `Shift+Esc`. The preview must be an `http`/`https` URL on `localhost`, `127.0.0.1`, or `[::1]` (any port, no credentials, at most 2048 characters); the tool and the server refuse anything else. Prefer `localhost` or `127.0.0.1`: CSP has no IPv6 source form, so browsers do not frame a `[::1]` preview, and Compare says so and offers the new tab. An app that refuses to be framed (`X-Frame-Options` or `frame-ancestors`) still opens with **Open in new tab**, which the Compare view always shows.
|
|
395
|
+
|
|
396
|
+
The canvas server binds `127.0.0.1` on a random port and needs a random per-server token in every URL. It rejects any `Host` other than its own loopback address, accepts every write (comments, Send all, resolve/reopen, Implement) only with its own `Origin` (`http://127.0.0.1:<port>` or `http://localhost:<port>`), a JSON body, and bounded lengths, keeps at most 500 comments per design, and serves only files under `design/` in the session cwd (design folders, plus exactly `design/system.html` for the system board), resolved by real path so neither `..` nor a symlink can escape. Artboards run in iframes sandboxed without `allow-same-origin`, so they cannot read the canvas or post comments themselves. The canvas may frame only loopback origins (its `frame-src`), and the Compare preview frame keeps its own origin (`allow-scripts allow-same-origin allow-forms allow-popups`, never top navigation) only because it is another origin than the canvas: the canvas refuses a preview on its own port, and sends no referrer, so the app never sees the token. No other network traffic is involved. The server and the tool write `comments.json` and `handoffs.json` one at a time through an atomic replace, and never overwrite a file they cannot parse.
|
|
397
|
+
|
|
398
|
+
### Gentle Music
|
|
399
|
+
|
|
400
|
+
`/gentle:music [mood]` hands the terminal to the [gentle-stream](https://github.com/Gentleman-Programming/gentle-stream) player, like Pi's external editor, passing the mood and the session model. In the player, `b` returns to Pi with the music playing and `q` returns and stops it. `/gentle:music next`, `pause`, `play`, `stop`, and `status` control the music without leaving Pi. Quitting Pi after using the command stops the music. gentle-stream runs from `PATH`, or through `uvx`/`uv` when it is not installed. See [Gentle Music](gentle-music.md).
|
|
401
|
+
|
|
332
402
|
### Bridge providers
|
|
333
403
|
|
|
334
404
|
Idle Claude Bridge continuation uses the normal user-prompt lifecycle so prompt preparation and tool declarations are retained. Gentle Agents hides only its exact, uniquely generated reserved wake in Pi's interactive transcript; child result and query cards remain visible. Native providers keep their hidden `display: false` custom wake.
|
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.
|