Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ The first-party `nan` provider is included; no third-party provider package is r
- **Streaming:** Pi streams chat completions through its OpenAI-compatible provider.
- **Model discovery:** Model discovery intersects NaN's authenticated `/v1/models` response with a maintained subset of known chat IDs from the [official model documentation](https://nan.builders/docs/models); unknown and non-chat IDs are omitted. A successful response with no known chat IDs stays empty. Documented context, reasoning, and text/image capabilities are preserved with conservative numeric bounds for abbreviated limits; audio input is not advertised by Pi.
- **Output caps:** The provider configures `maxTokens` caps rather than claiming undocumented model maxima: 32,768 for GLM 5.3, GLM 5.3 Flash, and MiMo; 16,384 for DeepSeek V4 Flash; 65,536 for Gemma 4 and Qwen 3.6; and 131,000 for Qwen 3.8 Flash (NaN documents 131K). Reasoning shares the output budget.
- **Offline fallback:** Before a successful refresh, all seven documented chat models are available as the offline fallback in `/gentle:models`: `glm5.3`, `deepseek-v4-flash`, `glm5.3-flash`, `qwen3.8-flash`, `mimo-v2.6-flash`, `gemma4`, and `qwen3.6`. This fallback declares documented support, not proof of access for your key. Once refreshed, the successful live key-scoped list remains authoritative (including an empty list), even offline or after a failed refresh. Changing credentials resets the catalog to the full documented fallback until discovery succeeds for the new key.
- **Offline fallback:** Before a successful refresh, all seven documented chat models are available as the offline fallback in `/gentle:profiles`: `glm5.3`, `deepseek-v4-flash`, `glm5.3-flash`, `qwen3.8-flash`, `mimo-v2.6-flash`, `gemma4`, and `qwen3.6`. This fallback declares documented support, not proof of access for your key. Once refreshed, the successful live key-scoped list remains authoritative (including an empty list), even offline or after a failed refresh. Changing credentials resets the catalog to the full documented fallback until discovery succeeds for the new key.
- **Not included:** NaN MCP search and media bridges are not included.

Thinking levels follow NaN's [reasoning contract](https://nan.builders/docs/models):
Expand Down Expand Up @@ -585,7 +585,7 @@ gentle-shell upgrade --rollback
- **Main channel:** On the main channel it rebuilds Gentle AI and Gentle Shell from the latest `main` commits (only what changed) and needs pnpm and Go (a Go older than the minimum is replaced, for the build only, by the pinned Go the installer left in its own folder); switching back to release restores the pinned Gentle AI binary. When the Gentle AI build fails but Gentle Shell moved, the new Gentle Shell is still installed and the command exits with an error asking you to run `gentle-shell upgrade --channel main` again. The retry rebuilds Gentle AI with the new Shell's code, and finishes once the cause of the original error is resolved.
- **Your Pi:** With pnpm 11, the updated Gentle Shell may run a newer Pi that pnpm puts next to it (always at least the minimum); your own Pi is never changed.
- **Bundled install:** A bundled install (the web installer's own Node, pnpm and Pi) follows the release channel only: it installs the new version beside the current one, verifies it, then switches, keeping the previous version for `--rollback`. On release, once the latest release publishes the bundled distribution, `upgrade` moves a global pnpm or npm installation to the bundled one and asks once before removing the old global `gentle-pi`.
- **`update` vs `upgrade`:** `gentle-shell update` is a different command: it is Pi's own package update. In a bundled install Pi ships pinned with Gentle Shell, so updating Pi itself runs `gentle-shell upgrade` instead.
- **`update` vs `upgrade`:** `gentle-shell update` is a different command: it is Pi's own package update. In a bundled install Pi ships pinned with Gentle Shell, so updating Pi itself runs `gentle-shell upgrade` instead. `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.

</details>

Expand Down
41 changes: 37 additions & 4 deletions bin/gentle-shell.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1684,6 +1684,32 @@ async function handleBundledUpgrade(bundled, commandArgs) {
}
}

// `gentle-shell update --latest` in a bundled install: the newest published
// Pi installed with this Gentle Shell beside the active version, without the
// release's verified lockfile (after a warning), verified, then `current`
// switched. Returns the exit code like handleBundledUpgrade; a failure leaves
// `current` as it was.
async function handleBundledPiLatest(bundled) {
const { prefixLayout, publishedPi, upgradePiLatest } = await import("../scripts/bundled-install.mjs");
const layout = prefixLayout({ platform: process.platform, env: process.env, home: homedir(), root: bundled.root });
try {
await upgradePiLatest({
layout,
home: homedir(),
shell: ownPackageVersion(),
platform: process.platform,
arch: process.arch,
env: process.env,
adapters: { latestPi: () => publishedPi(layout, { platform: process.platform, env: process.env }) },
out: (line) => process.stdout.write(`${line}\n`),
});
return 0;
} catch (error) {
process.stderr.write(`gentle-shell update: ${error.message}${error.stderr ? `\n${error.stderr}` : ""}\n`);
return 1;
}
}

// The bundled npm as the `npmCommand` of a home Gentle Shell owns (the isolated
// home, or a --home it created or provisioned; never --link or a foreign home),
// so Pi installs packages with our npm while its tools keep the user's PATH.
Expand Down Expand Up @@ -1933,14 +1959,21 @@ async function main() {

// S5: in a bundled install Pi updates only with Gentle Shell, so Pi's own
// update becomes `gentle-shell upgrade` (run when interactive, named
// otherwise); package updates still reach Pi.
// otherwise), or with `--latest` the newest published Pi without the
// release's lockfile (run even when not interactive: it was asked for);
// package updates still reach Pi.
let passthrough = args.passthrough;
if (bundled && args.piSubcommand === "update") {
const plan = bundledUpdatePlan(args.passthrough);
if (plan.self) {
const interactive = process.stdin.isTTY === true && process.stdout.isTTY === true;
for (const line of bundledUpdateNotice({ piVersion: versionCheck.version, interactive })) process.stdout.write(`${line}\n`);
const code = interactive ? await handleBundledUpgrade(bundled, []) : undefined;
let code;
if (plan.latest) {
code = await handleBundledPiLatest(bundled);
} else {
const interactive = process.stdin.isTTY === true && process.stdout.isTTY === true;
for (const line of bundledUpdateNotice({ piVersion: versionCheck.version, interactive })) process.stdout.write(`${line}\n`);
code = interactive ? await handleBundledUpgrade(bundled, []) : undefined;
}
const next = bundledUpdateNext(plan, code);
if ("exitCode" in next) process.exit(next.exitCode);
if (next.note) process.stderr.write(`${next.note}\n`);
Expand Down
27 changes: 24 additions & 3 deletions docs/gentle-music.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,36 @@ When you quit Pi after using `/gentle:music`, Gentle Shell runs `gentle-stream c
Gentle Shell looks for gentle-stream in this order:

1. `gentle-stream` on `PATH`.
2. `uvx`, running gentle-stream straight from its repository (the first run downloads it).
3. `uv`, through `uv tool run`.
2. In a bundled Gentle Shell, the gentle-stream it installed inside its own folder (see below).
3. `uvx`, running gentle-stream straight from its repository (the first run downloads it).
4. `uv`, through `uv tool run`.

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:
With none of them, a pnpm or npm install of Gentle Shell explains how to install and does nothing else. Install [uv](https://docs.astral.sh/uv/getting-started/installation/), or install gentle-stream permanently:

```bash
uv tool install 'gentle-stream[samples] @ git+https://github.com/Gentleman-Programming/gentle-stream'
```

### Installed by a bundled Gentle Shell

A bundled Gentle Shell (the one the web installer sets up) offers to install the player for you the first time `/gentle:music` finds none:

> Install the gentle-stream music player inside Gentle Shell? It downloads uv, Python 3.13 and the player (about 150 MB) into the Gentle Shell folder.

Decline and you get the manual hint above; nothing is downloaded. Accept and Gentle Shell shows its progress, installs the player, and starts the music. Later runs use it directly, with no question.

Everything stays inside the Gentle Shell folder (`~/.gentle-shell`, or `%LOCALAPPDATA%\gentle-shell` on Windows). Nothing is added to your `PATH`, and your own Python, uv, and uv settings are never used or changed:

| What | Where | Size on disk |
| :-- | :-- | :-- |
| [uv](https://github.com/astral-sh/uv) 0.13.6, the release archive pinned by sha256 and checked before use | `runtime/uv-0.13.6/` | about 30 MB |
| Python 3.13, managed by that uv | `music/python/` | about 70 MB |
| gentle-stream, from a pinned commit archive of its repository (git is not needed) | `music/tools/`, run from `music/bin/gentle-stream` | about 110 MB |

uv's download cache (`music/cache/`) is emptied after the install. Removing the bundled install removes all of it.

The player is installed with its `samples` extra (pyfluidsynth). If that extra cannot be installed, Gentle Shell says so and installs the player without it. Either way, the sampled instruments need the FluidSynth library from your system (for example `brew install fluid-synth` or `apt install libfluidsynth3`) and the soundfont `gentle-stream setup-samples` downloads; without them gentle-stream plays its synthesized instruments.

## Limits

- The player needs the interactive terminal. In RPC, JSON, and print modes, `/gentle:music` shows a notice and does nothing.
Expand Down
6 changes: 3 additions & 3 deletions docs/gentle-shell.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Source map: [shell extension](../extensions/gentle-shell.ts), [shell bar](../lib

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.

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.
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`, or with `gentle-shell update --latest` to the newest published Pi without the release's verified lockfile (after a warning that features relying on audited Pi internals, such as the Vim editor, may turn off; `upgrade` never downgrades it afterwards). See [managing packages](readme-reference.md#managing-packages) for the ownership contract.

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:

Expand Down Expand Up @@ -245,7 +245,7 @@ Gentle Shell ships its own interactive tools instead of depending on third-party

### Gentle Agents

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.2.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.
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.

The `subagent_*` tools and the agents card replace the third-party subagents package (remove `npm:pi-subagents-j0k3r` from your pi packages; while it is still installed the tools stay unregistered and a warning says so at startup). Agent definitions and settings are the ones you already have: markdown agents in `~/.pi/agent/agents/`, `~/.pi/agent/subagents/`, `<cwd>/.pi/agents/`, `<cwd>/.pi/subagents/` (project beats global, `subagents/` beats `agents/`), and `subagents.json` at the global and project level (`default_model`, `default_effort`, `default_mode`, `model_profiles`, `stall_timeout_ms`, `tool_stall_timeout_ms`, `max_concurrency`, `history_max_tasks`).

Expand Down Expand Up @@ -397,7 +397,7 @@ The canvas server binds `127.0.0.1` on a random port and needs a random per-serv

### Gentle Music

`/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).
`/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. A bundled Gentle Shell without any of them offers, with your consent, to install the player inside its own folder: a pinned, checksum-verified uv 0.13.6 in `runtime/`, and the uv-managed Python 3.13 and gentle-stream in `music/` (about 150 MB to download, about 210 MB on disk). A pnpm or npm install keeps the manual install hint. See [Gentle Music](gentle-music.md).

### Bridge providers

Expand Down
Loading
Loading