500 lines
22 KiB
Markdown
500 lines
22 KiB
Markdown
# Install ThothII on a local PC or Mac
|
|
|
|
This guide installs one loopback-only ThothII on the same Windows, macOS, or Linux computer that
|
|
runs Docker. The supported application is one Docker Compose distribution containing exactly
|
|
`frontend` and `core`; Pi is pinned inside `core`. DWH, vector database, embedding, and LLM remain
|
|
external configurable services even when they run on this computer.
|
|
|
|
No host Pi, Node.js, Python, Go toolchain, Docker socket in core, or browser shell is required.
|
|
Commands that contain example paths must be changed to absolute paths on your computer.
|
|
|
|
## Choose your platform
|
|
|
|
- **macOS:** use Terminal and Docker Desktop. Apple Silicon and Intel are supported by the local
|
|
image build.
|
|
- **Windows PowerShell:** use Docker Desktop with its WSL2 engine, Git for Windows, the Windows
|
|
build launcher, and `thothctl-windows-amd64.exe`.
|
|
- **Windows WSL2 (recommended):** enable Docker Desktop integration for your Linux distribution,
|
|
clone under `/home/<user>` rather than `/mnt/c`, and follow the Linux shell commands.
|
|
- **Linux PC:** use Docker Engine plus the Compose v2 plugin and the Linux `thothctl` binary.
|
|
|
|
Windows users must also read [Windows and WSL2 line endings](windows-line-endings.md) before the
|
|
first build.
|
|
|
|
## Prerequisites
|
|
|
|
Install only:
|
|
|
|
1. Git 2.39 or newer.
|
|
2. Docker Desktop on macOS/Windows, or Docker Engine on Linux.
|
|
3. Docker Compose v2 (`docker compose`, not legacy `docker-compose`).
|
|
4. About 10 GB of free disk for source, images, build cache, and initial volumes.
|
|
5. Network access to the workspace Git remote and configured DWH/vector/embedding/LLM endpoints.
|
|
|
|
Verify the tools:
|
|
|
|
```sh
|
|
git --version
|
|
docker version
|
|
docker compose version
|
|
docker run --rm hello-world
|
|
```
|
|
|
|
On Linux, add the operator to the Docker group only if local policy permits it; sign out and back
|
|
in afterward. A local installation needs no inbound firewall rule because ports bind only to
|
|
`127.0.0.1`.
|
|
|
|
## Clone and verify LF
|
|
|
|
Use a `git clone` command that disables automatic CRLF conversion for this checkout.
|
|
|
|
macOS and Linux:
|
|
|
|
```sh
|
|
git -c core.autocrlf=false clone https://github.example.invalid/your-org/ThothII.git
|
|
cd ThothII
|
|
git config --local core.autocrlf false
|
|
bash scripts/verify-line-endings.sh
|
|
```
|
|
|
|
Windows PowerShell:
|
|
|
|
```powershell
|
|
git -c core.autocrlf=false clone https://github.example.invalid/your-org/ThothII.git
|
|
Set-Location ThothII
|
|
git config --local core.autocrlf false
|
|
& "C:\Program Files\Git\bin\bash.exe" scripts/verify-line-endings.sh
|
|
```
|
|
|
|
Windows WSL2:
|
|
|
|
```sh
|
|
mkdir -p "$HOME/src" && cd "$HOME/src"
|
|
git -c core.autocrlf=false clone https://github.example.invalid/your-org/ThothII.git
|
|
cd ThothII
|
|
git config --local core.autocrlf false
|
|
bash scripts/verify-line-endings.sh
|
|
```
|
|
|
|
Stop if the verifier names any path. Do not build from a CRLF checkout.
|
|
|
|
## Create the local operator files
|
|
|
|
Copy the non-secret template. This untracked `.env` contains addresses and absolute source paths,
|
|
never secret values:
|
|
|
|
```sh
|
|
cp deploy/env/local.env.example deploy/env/local.env
|
|
mkdir -p /absolute/path/to/thothii-operator/secrets
|
|
chmod 0700 /absolute/path/to/thothii-operator/secrets
|
|
```
|
|
|
|
Native Windows PowerShell performs the same setup without POSIX utilities. The ACL commands remove
|
|
inherited access from the new operator directory and grant full control only to the current Windows
|
|
identity. Stop if either `icacls.exe` command returns a nonzero exit code:
|
|
|
|
```powershell
|
|
$OperatorDir = Join-Path $env:USERPROFILE 'thothii-operator'
|
|
$SecretsDir = Join-Path $OperatorDir 'secrets'
|
|
$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
|
|
if (Test-Path $OperatorDir) { throw 'Use a new operator directory or review its ACLs manually.' }
|
|
New-Item -ItemType Directory -Force -Path $OperatorDir, $SecretsDir | Out-Null
|
|
icacls.exe $OperatorDir /inheritance:r
|
|
if ($LASTEXITCODE -ne 0) { throw 'Could not remove inherited operator-directory ACLs.' }
|
|
icacls.exe $OperatorDir /grant:r "${CurrentUser}:(OI)(CI)F"
|
|
if ($LASTEXITCODE -ne 0) { throw 'Could not grant the current user the operator-directory ACL.' }
|
|
Copy-Item deploy/env/local.env.example deploy/env/local.env
|
|
Copy-Item docs/install/examples/thothii-installation.local.yaml `
|
|
(Join-Path $OperatorDir 'thothii-installation.yaml')
|
|
```
|
|
|
|
Edit `deploy/env/local.env`. At minimum set the workspace Git remote, `PI_AUTH_FILE`,
|
|
`THT_SECRETS_FILE`, and external service endpoints. Create the Pi/application and Git transport
|
|
files under the protected operator directory and set mode `0600`. On Windows use a user-only ACL
|
|
instead. DWH and Evidence credentials are entered later through Workspace management and stored
|
|
in the backend's encrypted `workspace-secrets` volume.
|
|
|
|
Do not paste credentials into this guide's commands, `.env`, workspace YAML, Git, URLs, image build
|
|
arguments, or the installation descriptor. Secret contents are mounted read-only under
|
|
`/run/secrets` (Pi's auth store has its own protected read-only mount) and must never be committed,
|
|
embedded, rendered, or logged.
|
|
|
|
Follow [the local workspace repository guide](local-workspace-registry.md) to choose exactly one
|
|
read-only Git SSH/HTTPS override. A fresh install requires a valid private workspace repository;
|
|
the remote Git repository remains the source of truth.
|
|
|
|
Copy the installation example to an operator-controlled file named exactly
|
|
`thothii-installation.yaml`, then replace all placeholders with absolute paths:
|
|
|
|
```sh
|
|
cp docs/install/examples/thothii-installation.local.yaml \
|
|
/absolute/path/to/thothii-operator/thothii-installation.yaml
|
|
```
|
|
|
|
For HTTPS, replace the SSH override in that file with `deploy/compose.git-https.yaml`. Add only
|
|
reviewed local overrides. Paths may contain spaces when correctly represented as YAML strings.
|
|
|
|
Native Windows uses the same four fields. Use single-quoted absolute Windows paths so backslashes
|
|
remain literal YAML characters:
|
|
|
|
```yaml
|
|
profile: local
|
|
projectDirectory: 'C:\Users\operator\src\ThothII'
|
|
envFile: 'C:\Users\operator\src\ThothII\deploy\env\local.env'
|
|
overrides:
|
|
- 'C:\Users\operator\src\ThothII\deploy\compose.git-ssh.yaml'
|
|
```
|
|
|
|
## Address external services
|
|
|
|
An address is interpreted inside `core`. Therefore container 127.0.0.1 means the container itself,
|
|
not the Docker host. Keep external DWH and LLM addresses configurable in the installation; Qdrant
|
|
and embedding are internal services in the standard stack.
|
|
|
|
- **Docker Desktop (macOS and Windows):** use `host.docker.internal`, for example
|
|
`http://host.docker.internal:11434`.
|
|
- **Linux:** if a service runs on the host, create an untracked override and include its absolute
|
|
path in `thothii-installation.yaml`:
|
|
|
|
```yaml
|
|
services:
|
|
core:
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway"
|
|
```
|
|
|
|
Then use `host.docker.internal` in the endpoint. `extra_hosts: host.docker.internal:host-gateway`
|
|
is a host routing aid, not a bundled service. Prefer a real DNS name for independently operated
|
|
services; retain TLS and authentication even when co-located.
|
|
|
|
## Build ThothII and thothctl
|
|
|
|
The canonical local Compose smoke uses the base file plus the local profile. Keep this exact
|
|
base+profile command available for install verification:
|
|
|
|
~~~sh
|
|
docker compose --env-file deploy/env/local.env + -f compose.yaml -f deploy/compose.local.yaml up --build -d
|
|
~~~
|
|
|
|
After the stack is ready, configure and check authentication with the single host CLI tht; see
|
|
the [local authentication guide](authentication-local.md). Authentication configuration is
|
|
installation-global and is checked before workspace tests.
|
|
|
|
From the repository root, macOS/Linux/WSL2 users run:
|
|
|
|
```sh
|
|
bash scripts/build-local.sh
|
|
bash scripts/build-thothctl.sh
|
|
```
|
|
|
|
Native PowerShell users run:
|
|
|
|
```powershell
|
|
powershell -ExecutionPolicy Bypass -File scripts/build-local.ps1
|
|
& "C:\Program Files\Git\bin\bash.exe" scripts/build-thothctl.sh
|
|
```
|
|
|
|
The second command uses Docker to create native operator binaries under `dist/thothctl`; users do
|
|
not need to know or install Go. Select `thothctl-darwin-arm64` or `-amd64` on macOS,
|
|
`thothctl-linux-amd64` or `-arm64` on Linux/WSL2, and `thothctl-windows-amd64.exe` on Windows.
|
|
Copy the selected file to the protected operator directory and, on macOS/Linux, run `chmod 0755`
|
|
on it.
|
|
|
|
## Start and verify
|
|
|
|
Set convenient variables (PowerShell users use `$THTCTL` and `$INSTALLATION` with `& $THTCTL`):
|
|
Every operator call has the form `thothctl --installation <absolute-descriptor> <command>`.
|
|
|
|
```sh
|
|
THTCTL=/absolute/path/to/thothii-operator/thothctl
|
|
INSTALLATION=/absolute/path/to/thothii-operator/thothii-installation.yaml
|
|
"$THTCTL" --installation "$INSTALLATION" update --check-only
|
|
"$THTCTL" --installation "$INSTALLATION" start
|
|
"$THTCTL" --installation "$INSTALLATION" status
|
|
"$THTCTL" --installation "$INSTALLATION" doctor
|
|
```
|
|
|
|
Native PowerShell uses the same order:
|
|
|
|
```powershell
|
|
$THTCTL = 'C:\Users\operator\thothii-operator\thothctl.exe'
|
|
$INSTALLATION = 'C:\Users\operator\thothii-operator\thothii-installation.yaml'
|
|
& $THTCTL --installation $INSTALLATION update --check-only
|
|
& $THTCTL --installation $INSTALLATION start
|
|
& $THTCTL --installation $INSTALLATION status
|
|
& $THTCTL --installation $INSTALLATION doctor
|
|
```
|
|
|
|
Wait for both services, then check the same-origin frontend and direct loopback core:
|
|
|
|
```sh
|
|
curl --fail http://127.0.0.1:8080/health
|
|
curl --fail http://127.0.0.1:8787/health
|
|
"$THTCTL" --installation "$INSTALLATION" pi doctor
|
|
"$THTCTL" --installation "$INSTALLATION" pi test
|
|
```
|
|
|
|
Native PowerShell must call `curl.exe` explicitly; Windows PowerShell may otherwise resolve `curl`
|
|
to `Invoke-WebRequest`:
|
|
|
|
```powershell
|
|
curl.exe --fail --silent --show-error http://127.0.0.1:8080/health
|
|
curl.exe --fail --silent --show-error http://127.0.0.1:8787/health
|
|
& $THTCTL --installation $INSTALLATION pi doctor
|
|
& $THTCTL --installation $INSTALLATION pi test
|
|
```
|
|
|
|
Open <http://127.0.0.1:8080>. If a check fails, run `thothctl ... logs` or `pi logs`; these are
|
|
bounded and sanitize declared secrets. Do not publish either loopback port.
|
|
|
|
## Update an installation
|
|
|
|
Commit or back up local operator changes first and finish active sessions. A promoted Pi image is
|
|
selected by the durable, installation-specific `current-image.yaml` after every base/profile file.
|
|
Therefore rebuilding `thothii-core:local` followed by `update --check-only` does not reconcile a
|
|
previous `pi update`: the old promoted core would remain selected.
|
|
|
|
Do not delete or edit the selector. `thothctl status` is the installation-aware selector test. If
|
|
the running core image is the base `thothii-core:local` image, no Pi update has promoted a durable
|
|
lifecycle image and an ordinary same-Pi-version source rebuild/start is supported. If status shows
|
|
a lifecycle image and the pulled Pi pin is unchanged, `pi update` would be a no-op and the procedure
|
|
must stop. A changed Pi pin uses transactional `pi update --source build` in either case.
|
|
|
|
macOS, Linux, and WSL2:
|
|
|
|
```sh
|
|
set -euo pipefail
|
|
|
|
abort_update() { printf 'Source update stopped: %s\n' "$1" >&2; exit 1; }
|
|
require_clean_source() {
|
|
local source_state
|
|
if ! source_state="$(git status --porcelain --untracked-files=all)"; then
|
|
abort_update "git status failed"
|
|
fi
|
|
[[ -z "$source_state" ]] || abort_update "commit, remove, or back up every tracked/untracked source change"
|
|
}
|
|
|
|
require_clean_source
|
|
if ! git pull --ff-only; then abort_update "git pull --ff-only failed"; fi
|
|
require_clean_source
|
|
if ! git config --local core.autocrlf false; then abort_update "could not set repository LF policy"; fi
|
|
if ! bash scripts/verify-line-endings.sh; then abort_update "the pulled checkout contains CRLF files"; fi
|
|
if ! SOURCE_REVISION="$(git rev-parse HEAD)"; then abort_update "could not record the pulled revision"; fi
|
|
if ! NEXT_PI_VERSION="$(sed -n 's/^ARG PI_VERSION=//p' docker/core.Dockerfile)"; then
|
|
abort_update "could not read the pulled Pi pin"
|
|
fi
|
|
[[ -n "$NEXT_PI_VERSION" && "$NEXT_PI_VERSION" != *$'\n'* ]] || abort_update "expected one pinned default PI_VERSION"
|
|
if ! INSTALLATION_STATUS="$("$THTCTL" --installation "$INSTALLATION" status)"; then
|
|
abort_update "thothctl status failed"
|
|
fi
|
|
if ! RUNNING_PI_VERSION="$("$THTCTL" --installation "$INSTALLATION" pi status)"; then
|
|
abort_update "thothctl pi status failed"
|
|
fi
|
|
RUNNING_PI_VERSION="${RUNNING_PI_VERSION#Pi version: }"
|
|
[[ -n "$RUNNING_PI_VERSION" ]] || abort_update "thothctl pi status returned no version"
|
|
|
|
COMPACT_STATUS="${INSTALLATION_STATUS//[[:space:]]/}"
|
|
USES_BASE_CORE=false
|
|
if [[ "$COMPACT_STATUS" == *'"Image":"thothii-core:local"'* ]]; then
|
|
USES_BASE_CORE=true
|
|
fi
|
|
TRANSACTIONAL_PI_UPDATE=true
|
|
if [[ "$NEXT_PI_VERSION" == "$RUNNING_PI_VERSION" ]]; then
|
|
[[ "$USES_BASE_CORE" == true ]] || abort_update "same Pi version is selected by a durable lifecycle image"
|
|
TRANSACTIONAL_PI_UPDATE=false
|
|
fi
|
|
|
|
if ! bash scripts/build-local.sh; then abort_update "the local image build failed"; fi
|
|
if ! bash scripts/build-thothctl.sh; then abort_update "the thothctl build failed"; fi
|
|
if ! "$THTCTL" --installation "$INSTALLATION" update --check-only; then
|
|
abort_update "the installation render check failed"
|
|
fi
|
|
if [[ "$TRANSACTIONAL_PI_UPDATE" == true ]]; then
|
|
if ! "$THTCTL" --installation "$INSTALLATION" pi update \
|
|
--version "$NEXT_PI_VERSION" --source build --yes --drain; then
|
|
abort_update "the transactional core update failed"
|
|
fi
|
|
fi
|
|
if ! "$THTCTL" --installation "$INSTALLATION" start; then abort_update "installation start failed"; fi
|
|
if ! curl --fail http://127.0.0.1:8080/health; then abort_update "frontend health check failed"; fi
|
|
if ! curl --fail http://127.0.0.1:8787/health; then abort_update "core health check failed"; fi
|
|
if ! FINAL_STATUS="$("$THTCTL" --installation "$INSTALLATION" status)"; then abort_update "final status failed"; fi
|
|
if ! FINAL_PI_STATUS="$("$THTCTL" --installation "$INSTALLATION" pi status)"; then abort_update "final pi status failed"; fi
|
|
[[ "${FINAL_PI_STATUS#Pi version: }" == "$NEXT_PI_VERSION" ]] || abort_update "running Pi version does not match the pulled pin"
|
|
if ! "$THTCTL" --installation "$INSTALLATION" doctor; then abort_update "final doctor failed"; fi
|
|
require_clean_source
|
|
printf 'Built source revision: %s\n%s\n%s\n' "$SOURCE_REVISION" "$FINAL_STATUS" "$FINAL_PI_STATUS"
|
|
```
|
|
|
|
Native Windows PowerShell uses the same fail-closed version comparison and transactional promotion:
|
|
|
|
```powershell
|
|
$ErrorActionPreference = 'Stop'
|
|
function Assert-NativeSuccess([string]$Step) {
|
|
if ($LASTEXITCODE -ne 0) { throw "$Step failed with exit code $LASTEXITCODE." }
|
|
}
|
|
function Assert-CleanSource {
|
|
$SourceState = @(git status --porcelain --untracked-files=all)
|
|
Assert-NativeSuccess 'git status'
|
|
if ($SourceState.Count -ne 0) {
|
|
throw 'Commit, remove, or back up every tracked/untracked source change.'
|
|
}
|
|
}
|
|
|
|
Assert-CleanSource
|
|
git pull --ff-only
|
|
Assert-NativeSuccess 'source pull'
|
|
Assert-CleanSource
|
|
git config --local core.autocrlf false
|
|
Assert-NativeSuccess 'repository LF policy'
|
|
& "C:\Program Files\Git\bin\bash.exe" scripts/verify-line-endings.sh
|
|
Assert-NativeSuccess 'pulled checkout LF verification'
|
|
$SourceRevision = git rev-parse HEAD
|
|
Assert-NativeSuccess 'source revision read'
|
|
$VersionLine = @(Select-String -Path docker/core.Dockerfile -Pattern '^ARG PI_VERSION=(.+)$')
|
|
if ($VersionLine.Count -ne 1) { throw 'Expected exactly one pinned default PI_VERSION.' }
|
|
$NextPiVersion = $VersionLine.Matches[0].Groups[1].Value
|
|
$InstallationStatus = @(& $THTCTL --installation $INSTALLATION status)
|
|
Assert-NativeSuccess 'installation status'
|
|
$RunningPiStatus = (& $THTCTL --installation $INSTALLATION pi status)
|
|
Assert-NativeSuccess 'Pi status'
|
|
$RunningPiVersion = $RunningPiStatus -replace '^Pi version:\s*', ''
|
|
if ([string]::IsNullOrWhiteSpace($RunningPiVersion)) { throw 'Pi status returned no version.' }
|
|
$Services = $InstallationStatus | ConvertFrom-Json
|
|
$CoreServices = @($Services | Where-Object { $_.Service -eq 'core' })
|
|
if ($CoreServices.Count -ne 1) { throw 'Installation status did not identify exactly one core service.' }
|
|
$UsesBaseCore = $CoreServices[0].Image -eq 'thothii-core:local'
|
|
$TransactionalPiUpdate = $true
|
|
if ($NextPiVersion -eq $RunningPiVersion) {
|
|
if (-not $UsesBaseCore) { throw 'Same Pi version is selected by a durable lifecycle image.' }
|
|
$TransactionalPiUpdate = $false
|
|
}
|
|
powershell -ExecutionPolicy Bypass -File scripts/build-local.ps1
|
|
Assert-NativeSuccess 'local image build'
|
|
& "C:\Program Files\Git\bin\bash.exe" scripts/build-thothctl.sh
|
|
Assert-NativeSuccess 'thothctl build'
|
|
& $THTCTL --installation $INSTALLATION update --check-only
|
|
Assert-NativeSuccess 'installation render check'
|
|
if ($TransactionalPiUpdate) {
|
|
& $THTCTL --installation $INSTALLATION pi update `
|
|
--version $NextPiVersion --source build --yes --drain
|
|
Assert-NativeSuccess 'transactional core update'
|
|
}
|
|
& $THTCTL --installation $INSTALLATION start
|
|
Assert-NativeSuccess 'installation start'
|
|
curl.exe --fail --silent --show-error http://127.0.0.1:8080/health
|
|
Assert-NativeSuccess 'frontend health check'
|
|
curl.exe --fail --silent --show-error http://127.0.0.1:8787/health
|
|
Assert-NativeSuccess 'core health check'
|
|
$FinalStatus = @(& $THTCTL --installation $INSTALLATION status)
|
|
Assert-NativeSuccess 'final installation status'
|
|
$FinalPiStatus = (& $THTCTL --installation $INSTALLATION pi status)
|
|
Assert-NativeSuccess 'final Pi status'
|
|
if (($FinalPiStatus -replace '^Pi version:\s*', '') -ne $NextPiVersion) {
|
|
throw 'Running Pi version does not match the pulled pin.'
|
|
}
|
|
& $THTCTL --installation $INSTALLATION doctor
|
|
Assert-NativeSuccess 'final doctor'
|
|
Assert-CleanSource
|
|
Write-Output "Built source revision: $SourceRevision"
|
|
Write-Output $FinalStatus
|
|
Write-Output $FinalPiStatus
|
|
```
|
|
|
|
The revision is printed only after every source/build/start/health/installation-aware check passes
|
|
and a final porcelain check still reports no tracked or untracked source changes. For a changed Pi
|
|
pin, status reports the promoted lifecycle candidate; for a same-version installation with no
|
|
selector, status reports the rebuilt base core. `update --check-only` alone proves only that Compose
|
|
renders.
|
|
Review release notes before updating. See [Pi management](pi-management.md) for rollback; never
|
|
install a package in the running container.
|
|
|
|
## Back up and restore
|
|
|
|
Back up before source/Pi updates and test restoration periodically. First stop cleanly:
|
|
|
|
```sh
|
|
"$THTCTL" --installation "$INSTALLATION" stop
|
|
docker volume ls --format '{{.Name}}' | grep '^thothii-'
|
|
```
|
|
|
|
Identify the four exact volumes belonging to this installation: `settings`, `pi-state`,
|
|
`workspace-registry`, and `sessions`. Confirm their Compose project label with `docker volume
|
|
inspect`. For each exact volume, archive it to a protected backup directory:
|
|
|
|
```sh
|
|
BACKUP_DIR=/absolute/path/to/backups/2026-08-05
|
|
VOLUME=exact-installation-volume-name
|
|
mkdir -p "$BACKUP_DIR"
|
|
docker run --rm -v "$VOLUME:/source:ro" -v "$BACKUP_DIR:/backup" \
|
|
alpine:3.22 tar -C /source -czf "/backup/$VOLUME.tgz" .
|
|
```
|
|
|
|
Native PowerShell can run the same read-only archive container:
|
|
|
|
```powershell
|
|
$BackupDir = 'C:\Users\operator\thothii-backups\2026-08-05'
|
|
$Volume = 'exact-installation-volume-name'
|
|
New-Item -ItemType Directory -Force $BackupDir | Out-Null
|
|
docker run --rm -v "${Volume}:/source:ro" -v "${BackupDir}:/backup" `
|
|
alpine:3.22 tar -C /source -czf "/backup/${Volume}.tgz" .
|
|
```
|
|
|
|
Also back up the installation descriptor, operator environment, generated overrides, and secret
|
|
files to separate encrypted/protected storage. Never commit them. Record image digests and the Git
|
|
revision. Do not back up while containers are running.
|
|
|
|
Restore only while stopped and only into a new, verified-empty exact target volume. Test the
|
|
archive in a disposable installation first:
|
|
|
|
```sh
|
|
TARGET_VOLUME=exact-empty-target-volume-name
|
|
ARCHIVE=/absolute/path/to/backups/2026-08-05/exact-volume-name.tgz
|
|
docker run --rm -v "$TARGET_VOLUME:/target" alpine:3.22 \
|
|
sh -c 'test -z "$(ls -A /target)"'
|
|
docker run --rm -v "$TARGET_VOLUME:/target" -v "$(dirname "$ARCHIVE"):/backup:ro" \
|
|
alpine:3.22 tar -C /target -xzf "/backup/$(basename "$ARCHIVE")"
|
|
```
|
|
|
|
Native PowerShell uses `Split-Path` to produce the read-only archive mount and archive name:
|
|
|
|
```powershell
|
|
$TargetVolume = 'exact-empty-target-volume-name'
|
|
$Archive = 'C:\Users\operator\thothii-backups\2026-08-05\exact-volume-name.tgz'
|
|
$ArchiveDir = Split-Path -Parent $Archive
|
|
$ArchiveName = Split-Path -Leaf $Archive
|
|
docker run --rm -v "${TargetVolume}:/target" alpine:3.22 `
|
|
sh -ceu 'test -z "$(ls -A /target)"'
|
|
if ($LASTEXITCODE -ne 0) { throw 'The restore target volume is not empty.' }
|
|
docker run --rm -v "${TargetVolume}:/target" -v "${ArchiveDir}:/backup:ro" `
|
|
alpine:3.22 tar -C /target -xzf "/backup/${ArchiveName}"
|
|
if ($LASTEXITCODE -ne 0) { throw 'The volume restore failed.' }
|
|
```
|
|
|
|
Restore all four volumes from the same backup set, restore protected operator files separately,
|
|
then run `update --check-only`, `start`, `doctor`, registry status/diagnostics, and a known session
|
|
before normal use. Never merge an archive into a non-empty volume.
|
|
|
|
## Data-preserving uninstall
|
|
|
|
Run `thothctl stop`, retain the installation descriptor at the same absolute path, and make one
|
|
verified backup set. In Docker Desktop, remove only this installation's stopped `core` and
|
|
`frontend` containers and optional local images; leave its four named volumes. On Linux, use the
|
|
containers' exact Compose project labels to remove only those stopped containers. Do not prune
|
|
global Docker data.
|
|
|
|
Do **not** run `docker compose down --volumes`: it deletes the application data this procedure is
|
|
meant to preserve. Keep the operator directory and protected secrets if you intend to reinstall.
|
|
Using the same descriptor path preserves the `thothctl` project identity and reconnects the same
|
|
named volumes after rebuilding the source checkout.
|
|
|
|
## Next: workspaces and Pi
|
|
|
|
Complete [local workspace-registry installation](local-workspace-registry.md), including Git trust,
|
|
bindings, pull, validation, diagnostics, and registry recovery. Then use [Pi management](pi-management.md)
|
|
for provider/model configuration, smoke testing, transactional update, and rollback.
|
|
|
|
The Git-backed workspace registry is always the workspace source of truth. Local DWH, vector,
|
|
embedding, or LLM processes remain independent services and are never added to the mandatory
|
|
ThothII core.
|