From a8623a2b18d8f872a94b8a73993e39914d0cb740 Mon Sep 17 00:00:00 2001 From: mptyl Date: Fri, 14 Aug 2026 18:34:04 +0200 Subject: [PATCH] docs: clarify Pi reload and update workflows --- docs/contracts/thothctl-pi.md | 60 +++++++-- docs/general/pi-configuration.md | 6 + docs/install/pi-management.md | 164 +++++++++++------------ scripts/verify-workspace-install-docs.sh | 21 ++- 4 files changed, 147 insertions(+), 104 deletions(-) diff --git a/docs/contracts/thothctl-pi.md b/docs/contracts/thothctl-pi.md index decd0f60..3b56ddb2 100644 --- a/docs/contracts/thothctl-pi.md +++ b/docs/contracts/thothctl-pi.md @@ -65,6 +65,37 @@ this protection and are unsupported. Advanced documented Compose rendering must `scripts/compose-with-preflight.sh` and include the same selector with `-f` when present; connector secret overrides must never bypass that preflight wrapper. +## Reloading Pi configuration + +Configuration reload is a separate lifecycle operation from an image update: + +```text +thothctl --installation /absolute/path/thothii-installation.yaml pi restart --yes [--drain] +``` + +`--yes` is required after reviewing the planned core recreation. Restart activates the durable +maintenance gate before it checks sessions. Without `--drain`, active open sessions refuse the +command. With `--drain`, the command polls the authenticated session inventory until no active +sessions remain; it never terminates sessions and the wait is bounded. + +Restart retains the exact current image and does not build, pull, select, tag, or upgrade an image. +It recreates only `core` with `--no-deps --force-recreate`; `frontend` and named volumes are not +recreated. Before reopening admission, it verifies health, the unchanged Pi version, the +provider/model/settings smoke, unchanged non-secret rendered configuration, the current image +identity, and the complete persistence-mount fingerprint. + +Restart and update keep separate recovery state: + +```text +/.thothctl//restart-state.json +/.thothctl//update-state.json +``` + +The files are mode `0600` and share one installation lifecycle lock, so a restart cannot race an +update. A restart refuses an incomplete update or restart state. After core mutation, a failure +leaves admission gated and preserves `restart-state.json`; the operator must use status/logs and +maintenance recovery rather than deleting state files. + ## Updating Pi Every update requires a pinned version, an explicit source, and confirmation: @@ -117,14 +148,16 @@ Recovery state and lock diagnostics live under: ```text /.thothctl//update-state.json -/.thothctl//update-state.json.lock.owner.json +/.thothctl//restart-state.json +/.thothctl//*.lock.owner.json ``` -The recovery file is mode `0600` and records transaction-scoped image identities, mount -fingerprints, target version/source, configuration digest, phase, and timestamp. It contains no -credentials, endpoint values, secret paths, Compose output, or logs. A cross-platform OS advisory -file lock serializes lifecycle operations; a crashed owner releases the lock automatically. Owner -metadata is diagnostic only and cannot wedge acquisition if empty, partial, or stale. +Each recovery file is mode `0600`. Update state records transaction-scoped image identities, mount +fingerprints, target version/source, configuration digest, phase, and timestamp; restart state +records the retained image and its verification inputs. Neither file contains credentials, endpoint +values, secret paths, Compose output, or logs. A cross-platform OS advisory file lock serializes +both lifecycle operations; a crashed owner releases the lock automatically. Owner metadata is +diagnostic only and cannot wedge acquisition if empty, partial, or stale. Any post-candidate failure explicitly confirms or reactivates maintenance and rescans sessions before compensation. Automatic rollback selects the transaction's previous image through the @@ -149,13 +182,14 @@ thothctl --installation /absolute/path/thothii-installation.yaml pi maintenance thothctl --installation /absolute/path/thothii-installation.yaml pi maintenance recover --yes ``` -`maintenance recover` completes an interrupted verified-image promotion, safely finalizes a -preparation interrupted before core mutation, and refuses other pending mutations. For terminal or -absent recovery state, it removes only a stale transaction override, verifies the running -installation when the gate is active, and only then removes the durable marker and reopens -admission. It never removes `current-image.yaml`. If rollback or recovery fails, leave the marker -in place, preserve `update-state.json`, repair the reported Docker/configuration issue, and rerun -rollback or maintenance recovery. +`maintenance recover` verifies and removes an interrupted restart state before it processes update +state. It completes an interrupted verified-image promotion, safely finalizes a preparation +interrupted before core mutation, and refuses other pending mutations. For terminal or absent +recovery state, it removes only a stale transaction override, verifies the running installation +when the gate is active, and only then removes the durable marker and reopens admission. It never +removes `current-image.yaml`. If rollback or recovery fails, leave the marker in place, preserve +the relevant recovery state, repair the reported Docker/configuration issue, and rerun rollback or +maintenance recovery. Missing confirmation, invalid arguments, active sessions, and an interrupted transaction exit `2`. Docker and verification failures exit nonzero with concise, redacted guidance. Direct diff --git a/docs/general/pi-configuration.md b/docs/general/pi-configuration.md index d8db2eae..86a6d912 100644 --- a/docs/general/pi-configuration.md +++ b/docs/general/pi-configuration.md @@ -2,6 +2,12 @@ Pi (il coding agent che orchestra il workflow NL→SQL) può risolvere un `provider/model` in tre modi diversi. Non sono alternativi: coesistono, e la scelta di quale usare dipende da **quanto è standard l'endpoint** e da **quanto deve essere ampia la visibilità** del modello (tutti i progetti vs. un progetto solo). +> **ThothII operator note:** ThothII runs Pi only in Docker Compose. Paths under +> `~/.pi/agent/` in this document describe Pi's container-side behavior. Operators edit +> `deploy/pi/models.json` and `deploy/pi/settings.json` in the ThothII project root and use +> the protected host credential file selected by `PI_AUTH_FILE`; they do not edit files inside +> the running container. + ## Credenziali nel backend container In produzione configurare una sola sorgente generica: il bundle `THT_SECRETS_FILE` con la voce diff --git a/docs/install/pi-management.md b/docs/install/pi-management.md index de351382..26c62751 100644 --- a/docs/install/pi-management.md +++ b/docs/install/pi-management.md @@ -1,88 +1,91 @@ # Pi management -Pi is pinned inside the ThothII `core` image. A local Pi, Node.js, Python, or Go installation is -not required. The browser can manage safe runtime settings, while the host-side `thothctl` -operator CLI performs container lifecycle and image updates. The core does not mount the Docker socket, -and there is no browser shell. +ThothII bundles Pi in the `core` image. Operators use the Pi Management page for safe application +defaults and the host-side `thothctl` CLI for lifecycle work. A local Pi installation is not +required; the core container does not mount the Docker socket and there is no browser shell. In the commands below, replace `/absolute/path/to/thothii-installation.yaml` with the protected installation descriptor created by the [local installation guide](local.md). -## Who can use Pi Management - -On the loopback-only local profile (`AUTH_MODE=none`), the person using that PC can open Pi -Management and change installation defaults or run diagnostics. Do not expose ports 8080 or 8787 -to another machine. - -On a public server, Pi Management requires upstream authentication and a trusted administrator -claim supplied by the authenticated reverse proxy. Without that claim the API returns -`403 pi_management_forbidden`; ordinary users cannot change installation-wide Pi settings. Image -updates are never available from the web page on either profile. - -## Use the Pi Management page - -Open ThothII, choose **Pi Management**, and check the bundled version and readiness. The page: - -- offers only supported provider, model, and reasoning choices; -- saves non-secret defaults; -- reports credentials only as present or missing; -- runs a bounded provider smoke test; and -- shows at most 200 sanitized log lines. - -It never displays or accepts a credential, runs an image update, or opens a terminal. Per-user -browser preferences remain separate from installation defaults. - -## Use thothctl - -Set a short shell variable for the platform-specific executable. Examples below use macOS/Linux: - ```sh THTCTL=/absolute/path/to/thothctl INSTALLATION=/absolute/path/to/thothii-installation.yaml ``` -The complete Pi command set is: +## Choose application defaults + +Use the **Pi Management** page to select the supported provider, model, and reasoning default, then +choose **Save defaults**. The page shows credentials only as present or missing and can run bounded +diagnostics; it never accepts or displays a credential, opens a terminal, or updates an image. + +Alternatively, use the CLI from an administrator terminal: + +```sh +"$THTCTL" --installation "$INSTALLATION" pi configure +"$THTCTL" --installation "$INSTALLATION" pi configure --provider zai --model glm-5.2 --thinking medium +``` + +Use GUI Save defaults or CLI `pi configure`, not both for the same change. The CLI's interactive +choices are restricted to supported models; non-interactive use must supply all three values. + +Useful read-only checks are: ```sh "$THTCTL" --installation "$INSTALLATION" pi status "$THTCTL" --installation "$INSTALLATION" pi doctor "$THTCTL" --installation "$INSTALLATION" pi test "$THTCTL" --installation "$INSTALLATION" pi check -"$THTCTL" --installation "$INSTALLATION" pi configure -"$THTCTL" --installation "$INSTALLATION" pi configure --provider zai --model glm-5.2 --thinking medium "$THTCTL" --installation "$INSTALLATION" pi logs -"$THTCTL" --installation "$INSTALLATION" pi maintenance status ``` -- `pi status` reads the image-bundled version. -- `pi doctor` checks the version boundaries, core health, settings, and configured model. -- `pi test` runs the isolated Pi/core smoke; `pi check` is its alias. -- `pi configure` presents closed choices on a terminal. Non-interactive use requires all three - flags. Never pass a credential as an argument. -- `pi logs` returns a bounded, sanitized snapshot and deliberately has no follow mode. -- `pi maintenance status` reports whether new session admission is gated. +`pi check` is an alias for `pi test`; logs are a sanitized, bounded snapshot with no follow mode. -Use `thothctl status`, `doctor`, `logs`, `start`, `stop`, and `update --check-only` for the wider -installation. Direct Compose lifecycle commands can bypass the durable image selector and are not -the normal operator interface. +## Edit the provider catalog and enabled-model policy -## Handle credentials and secrets +Edit these project-root files in source control, then review and deploy the change through the +normal project process: -Keep provider credentials in the protected host file named by `PI_AUTH_FILE`, or in the documented -model secret file/bundle. Compose mounts protected material read-only under `/run/secrets` or at -Pi's protected auth path. Apply mode `0600` on macOS/Linux or a user-only ACL on Windows. +- `deploy/pi/models.json` is the provider catalog: provider endpoints and the models each provider + offers. +- `deploy/pi/settings.json` is the enabled-model policy and application defaults. -Never put secret text in the installation YAML, operator environment, workspace Git repository, -command arguments, browser, screenshots, tickets, rendered Compose, or logs. Pi configuration is -declarative: executable `!command` values are rejected. Use supported environment references or -the protected credential files. +These files contain configuration, not credentials. Keep provider configuration declarative: Pi +management rejects executable `!command` values. Do not edit generated files, the running +container, or a host-native Pi directory. -After rotating a credential, restart core through `thothctl stop` and `thothctl start`, then run -`pi doctor` and `pi test`. Do not print the file while troubleshooting. +## Store provider credentials -## Update and roll back Pi +`PI_AUTH_FILE` is a setting in the installation environment file (for example, +`deploy/env/local.env`). Its value is the absolute path of the protected host credential file that +this installation selects. Docker Compose mounts that selected file read-only for Pi. +Other declared protected material is likewise mounted read-only under `/run/secrets`. -Finish or close active work first. A build update uses source already present in this checkout: +Set restrictive permissions on the host file (`0600` on macOS/Linux or a user-only ACL on Windows). +Never put its contents in installation YAML, Git, command arguments, the browser, screenshots, +tickets, rendered Compose output, or logs. Do not print the file while troubleshooting. + +## Reload changed configuration + +After changing the provider catalog, enabled-model policy, or selected credential file, reload the +running application with one confirmed restart: + +```sh +"$THTCTL" --installation "$INSTALLATION" pi restart --yes --drain +``` + +`--yes` confirms that core will be recreated. Without `--drain`, restart refuses active sessions; +with it, ThothII closes admission and waits for active sessions to finish without terminating them. +The wait is bounded. Restart retains the current image: it does not build, pull, select, or upgrade +an image. It will restart only core, then verifies health, Pi version, settings/model smoke, +non-secret rendered configuration, and persistence mounts before reopening admission. + +Use `pi restart --yes` when there are already no active sessions. Do not substitute `thothctl stop` +and `thothctl start` or raw Compose commands for this reload workflow. + +## Update the bundled Pi version + +`pi update` is for a new bundled Pi version; it is not a configuration reload. Finish or drain +active work, then choose an explicit source and version. A build update uses this checkout: ```sh "$THTCTL" --installation "$INSTALLATION" pi update \ @@ -98,29 +101,25 @@ A registry update must use an immutable digest, never a mutable tag: --yes --drain ``` -The operation gates new sessions, records non-secret recovery state, recreates only `core`, checks -the requested version, health, settings, smoke request, configuration, and persistence mounts, -then promotes the verified image. Frontend and named volumes are preserved. +Update keeps new-session admission gated while it builds or pulls a candidate, recreates only +`core`, verifies it, and promotes the image only after success. It preserves the frontend and named +volumes. -To restore the image recorded by the interrupted or latest update: +## Recover a failed lifecycle operation -```sh -"$THTCTL" --installation "$INSTALLATION" pi rollback --yes -``` - -## Recover a failed update - -Do not delete `.thothctl`, `update-state.json`, `current-image.yaml`, containers, or volumes. First -inspect the durable gate and sanitized logs: +If a restart or update fails after core recreation, leave maintenance enabled and preserve the +reported recovery state. Do not delete `.thothctl`, state files, containers, or volumes. Inspect +status and sanitized logs, then restore the previous image when an update is involved: ```sh "$THTCTL" --installation "$INSTALLATION" pi maintenance status +"$THTCTL" --installation "$INSTALLATION" pi status "$THTCTL" --installation "$INSTALLATION" pi logs "$THTCTL" --installation "$INSTALLATION" pi rollback --yes ``` -If rollback reports a terminal or stale maintenance state, repair the reported Docker, disk, or -configuration problem, then run: +Repair the reported Docker, disk, or configuration problem, then have ThothII complete the safe +recovery path: ```sh "$THTCTL" --installation "$INSTALLATION" pi maintenance recover --yes @@ -128,19 +127,14 @@ configuration problem, then run: "$THTCTL" --installation "$INSTALLATION" pi test ``` -If recovery still fails, leave maintenance active and preserve the recovery file. Collect only -sanitized `pi logs`, `status`, and `doctor` output for support; do not ungate the installation by -editing state files. +`pi rollback --yes` restores the prior update image. `pi maintenance recover --yes` checks both +restart and update recovery state before it can reopen admission. If either command fails, keep the +installation gated and collect only the sanitized diagnostics. ## Direct support access -Raw Compose access is unsupported: there is no public operator command that safely reconstructs -the installation's hashed project name, project directory, environment file, optional overrides, -and durable current-image selector for ad-hoc Pi execution. Do not approximate those arguments or -delete/edit lifecycle state for support. - -Route direct executable/version checks through `thothctl pi status`, and collect diagnostics with -`thothctl pi doctor`, `thothctl pi test`, and `thothctl pi logs`. These commands are -installation-aware and redact declared secret values. Share only their sanitized output. Do not -run package installers, alter Pi files inside the live container, mount the Docker socket, expose -a browser shell, or use a host Pi as a substitute. +Raw Compose access is unsupported because it can bypass the installation-specific environment and +durable image selector. For support, use the installation-aware `thothctl pi status`, +`thothctl pi doctor`, `thothctl pi test`, and `thothctl pi logs` commands. Do not run package +installers, alter files inside the live container, mount the Docker socket, expose a browser shell, +or use a host Pi as a substitute. diff --git a/scripts/verify-workspace-install-docs.sh b/scripts/verify-workspace-install-docs.sh index 72d0674a..0b8eef3f 100755 --- a/scripts/verify-workspace-install-docs.sh +++ b/scripts/verify-workspace-install-docs.sh @@ -1136,12 +1136,12 @@ verify_pi_management_guide() { return 1 } require_headings "$guide" "Pi management guide" \ - "Who can use Pi Management" \ - "Use the Pi Management page" \ - "Use thothctl" \ - "Handle credentials and secrets" \ - "Update and roll back Pi" \ - "Recover a failed update" \ + "Choose application defaults" \ + "Edit the provider catalog and enabled-model policy" \ + "Store provider credentials" \ + "Reload changed configuration" \ + "Update the bundled Pi version" \ + "Recover a failed lifecycle operation" \ "Direct support access" require_text "$guide" "Pi management guide" \ "pi status" \ @@ -1149,6 +1149,11 @@ verify_pi_management_guide() { "pi test" \ "pi check" \ "pi configure" \ + "pi restart --yes --drain" \ + "restart only core" \ + "deploy/pi/models.json" \ + "deploy/pi/settings.json" \ + "PI_AUTH_FILE" \ "pi update" \ "pi rollback --yes" \ "pi maintenance status" \ @@ -1158,6 +1163,10 @@ verify_pi_management_guide() { "Raw Compose access is unsupported" \ "no browser shell" \ "does not mount the Docker socket" + if grep -Fq '~/.pi/agent/' "$guide"; then + echo "Pi management guide must not direct ThothII operators to native Pi paths" >&2 + return 1 + fi node - "$guide" <<'NODE' const fs = require("fs"); const source = fs.readFileSync(process.argv[2], "utf8");