diff --git a/CLAWDIE-ISO.md b/CLAWDIE-ISO.md index 788dc07..dff8890 100644 --- a/CLAWDIE-ISO.md +++ b/CLAWDIE-ISO.md @@ -341,8 +341,8 @@ clawdie-iso/ Derived from `setup/environment.ts` host baseline + desktop-installer + DE packages: **Clawdie host baseline:** -`node24`, `npm`, `bsddialog`, `bastille`, `git`, `tmux`, `python311`, `uv`, -`ripgrep`, `fd-find`, `rsync`, `postgresql18-client`, `py311-pillow`, `dejavu` +`node24`, `npm`, `bsddialog`, `bastille`, `git`, `tmux`, `python312`, `uv`, +`ripgrep`, `fd-find`, `rsync`, `postgresql18-client`, `dejavu` **Xorg baseline:** `xorg-minimal`, `xf86-video-intel`, `drm-kmod`, diff --git a/README-CLAWDIE.md b/README-CLAWDIE.md index a2fb63c..fc2641f 100644 --- a/README-CLAWDIE.md +++ b/README-CLAWDIE.md @@ -53,7 +53,7 @@ See [docs/public/architecture/warden.md](docs/public/architecture/warden.md). git clone https://codeberg.org/Clawdie/Clawdie-AI.git /home/clawdie/clawdie-ai cd /home/clawdie/clawdie-ai -pkg install node24 npm git python312 py312-uv rsync +pkg install node24 npm git python312 uv rsync npm install npm install -g @earendil-works/pi-coding-agent # If setup.sh did not launch onboarding automatically: @@ -102,12 +102,14 @@ The current FreeBSD deployment depends on: ### `controlplane` Role: + - main Clawdie control-plane jail - Telegram intake - scheduling - Warden task dispatch Profile: + - `freebsd-jail` - `thick` - `vnet` @@ -116,10 +118,12 @@ Profile: ### `db` Role: + - PostgreSQL memory backend - persistent service Profile: + - `freebsd-jail` - `thick` - `vnet` @@ -134,19 +138,23 @@ Profile: ## Snapshot Policy Manual milestone snapshots: + - human-named - day-first - month abbreviation Examples: + - `@postgres18-ready-08.mar.2026` - `@fresh-08.mar.2026` Automatic snapshots: + - handled by Sanoid - keep Sanoid's internal `autosnap_...` naming Current automated Sanoid targets: + - `zroot/clawdie-runtime/jails/db` - `zroot/clawdie-runtime/jails/controlplane` diff --git a/README.md b/README.md index a17a24d..0e22b7b 100644 --- a/README.md +++ b/README.md @@ -155,12 +155,12 @@ just setup-cms # npm run setup -- --step cms - Internet access for `pkg` and `npm` - `bash` and `git` available before first run - **`just`** — command runner (`pkg install just` on FreeBSD; preinstalled on Clawdie ISO) -- **At least one agent CLI on `PATH`**: one of `pi`, `aider`, `claude`, `codex`, or `gemini`. The controlplane harness uses Aider+Pi as the primary driver. Onboarding fails fast if none are present (see [`doc/AGENT-CLI-VALIDATION.md`](doc/AGENT-CLI-VALIDATION.md) for the validated install paths). The Clawdie ISO ships claude/gemini/pi via the npm-globals bundle, aider via `py311-aider_chat` pkg, and codex via `pkg install codex`. +- **At least one agent CLI on `PATH`**: one of `pi`, `aider`, `claude`, `codex`, or `gemini`. The controlplane harness uses Aider+Pi as the primary driver. Onboarding fails fast if none are present (see [`doc/AGENT-CLI-VALIDATION.md`](doc/AGENT-CLI-VALIDATION.md) for the validated install paths). The Clawdie ISO ships claude/gemini/pi via the npm-globals bundle, provisions Aider in a Python 3.12 venv, and includes codex via `pkg install codex`. Recommended explicit host baseline before first run: ```sh -sudo pkg install -y bash git bastille node24 npm tmux btop python311 uv ripgrep fd-find rsync postgresql18-client py311-pillow dejavu py311-aider_chat edk2-bhyve just +sudo pkg install -y bash git bastille node24 npm tmux btop python312 uv ripgrep fd-find rsync postgresql18-client dejavu edk2-bhyve just ``` The `edk2-bhyve` package provides UEFI firmware required for optional browser-vm support @@ -169,15 +169,16 @@ The `edk2-bhyve` package provides UEFI firmware required for optional browser-vm On FreeBSD, use `fd-find`. It provides the `fd` command that `pi` expects and avoids colliding with the unrelated `fd` file manager package. -The host baseline also includes `py311-pillow` and `dejavu` so tmux screenshot -capture works without a separate `uv pip install Pillow` step. +Python package-flavored extras stay out of the baseline until the FreeBSD +quarterly repository publishes Python 3.12 flavors. Install Aider/Pillow-style +tools into explicit Python 3.12 venvs when needed. -If the host still has both Python 3.11 and 3.12 installed, pin `uv` to 3.11 +If the host still has multiple Python minors installed, pin `uv` to 3.12 explicitly until the generic `python3` path is cleaned up: ```sh -uv venv --python 3.11 -uv run --python 3.11 +uv venv --python 3.12 +uv run --python 3.12 ``` ### Operator Glasspane @@ -215,7 +216,7 @@ First use: ```bash # 1. Install the recommended FreeBSD host baseline -sudo pkg install -y bash git bastille node24 npm tmux btop python311 uv ripgrep fd-find rsync postgresql18-client py311-pillow dejavu py311-aider_chat just +sudo pkg install -y bash git bastille node24 npm tmux btop python312 uv ripgrep fd-find rsync postgresql18-client dejavu just # 2. Clone the repository git clone https://codeberg.org/Clawdie/Clawdie-AI.git /home/clawdie/clawdie-ai diff --git a/doc/AIDER-FREEBSD-INSTALL.md b/doc/AIDER-FREEBSD-INSTALL.md index 44103e2..6ff3088 100644 --- a/doc/AIDER-FREEBSD-INSTALL.md +++ b/doc/AIDER-FREEBSD-INSTALL.md @@ -30,26 +30,22 @@ export PATH=/opt/clawdie/cargo/bin:$PATH ## Working install (tested) -1) Install Aider from packages (adds many deps but works): +1. Create a project-local Python 3.12 venv. The FreeBSD quarterly repo still + publishes only older Python-flavored Aider packages, so keep Aider out of the + host pkg baseline and install it into a venv: ```sh -sudo pkg install py311-aider_chat +python3.12 -m venv /home/clawdie/clawdie-ai/tmp/aider-venv ``` -2) Create a project-local venv that can override litellm: - -```sh -python3.11 -m venv --system-site-packages /home/clawdie/clawdie-ai/tmp/aider-venv -``` - -3) Upgrade Aider + pin litellm to the expected version inside the venv: +2. Upgrade Aider + pin litellm to the expected version inside the venv: ```sh /home/clawdie/clawdie-ai/tmp/aider-venv/bin/pip install --no-user --no-deps --upgrade --ignore-installed aider-chat==0.86.2 /home/clawdie/clawdie-ai/tmp/aider-venv/bin/pip install --no-user --no-deps --upgrade --ignore-installed litellm==1.81.10 ``` -4) Align tree-sitter with the system tree-sitter-languages package (fixes repo-map crash): +3. Align tree-sitter with the system tree-sitter-languages package (fixes repo-map crash): ```sh env TMPDIR=/home/clawdie/clawdie-ai/tmp \ @@ -63,7 +59,7 @@ FreeBSD ships `tree_sitter_languages` from packages (1.10.2) which expects TypeError: __init__() takes exactly 1 argument (2 given) ``` -4) Run Aider (use the venv binary): +4. Run Aider (use the venv binary): ```sh env AIDER_ANALYTICS_DISABLE=1 /home/clawdie/clawdie-ai/tmp/aider-venv/bin/aider \ diff --git a/infra/packages/host-baseline.txt b/infra/packages/host-baseline.txt index 7b15b4b..c318f7a 100644 --- a/infra/packages/host-baseline.txt +++ b/infra/packages/host-baseline.txt @@ -9,19 +9,18 @@ tmux btop bsddialog codex -python311 +python312 uv ripgrep fd-find rsync postgresql18-client dnsmasq -py311-pillow dejavu rust -# Controlplane harness (Aider + Pi multi-agent orchestrator) -py311-aider_chat +# Controlplane harness helpers. Aider is installed into a venv until the +# quarterly FreeBSD repo publishes a Python 3.12 package flavor. just # Wayland display stack — used by worker jails (cage) and operator sessions diff --git a/setup.sh b/setup.sh index cd92643..b365a91 100755 --- a/setup.sh +++ b/setup.sh @@ -71,8 +71,8 @@ install_host_pkg_baseline() { tmux) command -v tmux >/dev/null 2>&1 || missing_pkgs+=("$pkg") ;; - python311) - command -v python3 >/dev/null 2>&1 || missing_pkgs+=("$pkg") + python312) + command -v python3.12 >/dev/null 2>&1 || missing_pkgs+=("$pkg") ;; uv) command -v uv >/dev/null 2>&1 || missing_pkgs+=("$pkg") @@ -92,9 +92,6 @@ install_host_pkg_baseline() { rust) command -v rustc >/dev/null 2>&1 || missing_pkgs+=("$pkg") ;; - py311-pillow) - python3 -c "import PIL" >/dev/null 2>&1 || missing_pkgs+=("$pkg") - ;; dejavu) [ -f /usr/local/share/fonts/dejavu/DejaVuSansMono.ttf ] || missing_pkgs+=("$pkg") ;; diff --git a/setup/agent-cli-check.ts b/setup/agent-cli-check.ts index 4828620..0cd9b2e 100644 --- a/setup/agent-cli-check.ts +++ b/setup/agent-cli-check.ts @@ -38,7 +38,7 @@ export class NoAgentCliError extends Error { [ 'No agent CLI found on PATH.', 'Clawdie needs pi and aider for the Aider+Pi controlplane harness.', - 'Install via the ISO bundle or: pkg install py311-aider_chat, npm install -g @earendil-works/pi-coding-agent.', + 'Install via the ISO bundle or: npm install -g @earendil-works/pi-coding-agent; install Aider in a Python 3.12 venv if needed.', 'Alternative CLIs (claude, codex, gemini) are also accepted.', ].join(' '), ); diff --git a/setup/environment.ts b/setup/environment.ts index 2b51627..05ed184 100644 --- a/setup/environment.ts +++ b/setup/environment.ts @@ -51,7 +51,7 @@ const HOST_PREREQUISITE_CHECKS: Record< dnsmasq: { key: 'DNSMASQ', check: () => commandExists('dnsmasq') }, tmux: { key: 'TMUX', check: () => commandExists('tmux') }, btop: { key: 'BTOP', check: () => commandExists('btop') }, - python311: { key: 'PYTHON3', check: () => commandExists('python3') }, + python312: { key: 'PYTHON3', check: () => commandExists('python3.12') }, uv: { key: 'UV', check: () => commandExists('uv') }, ripgrep: { key: 'RIPGREP', check: () => commandExists('rg') }, 'fd-find': { key: 'FD', check: () => commandExists('fd') }, @@ -60,20 +60,8 @@ const HOST_PREREQUISITE_CHECKS: Record< tailscale: { key: 'TAILSCALE', check: () => commandExists('tailscale') }, just: { key: 'JUST', check: () => commandExists('just') }, rust: { key: 'RUST', check: () => commandExists('rustc') }, - 'py311-aider_chat': { key: 'AIDER', check: () => commandExists('aider') }, node24: { key: 'NODE', check: () => commandExists('node') }, npm: { key: 'NPM', check: () => commandExists('npm') }, - 'py311-pillow': { - key: 'PILLOW', - check: () => { - try { - execSync('python3 -c "import PIL"', { stdio: 'ignore' }); - return true; - } catch { - return false; - } - }, - }, dejavu: { key: 'DEJAVU_FONT', check: () => @@ -111,11 +99,9 @@ export async function run(_args: string[]): Promise { const service = commandExists('service'); const sudo = commandExists('sudo'); const jailConf = fs.existsSync('/etc/jail.conf'); - const hasPython311 = commandExists('python3.11'); const hasPython312 = commandExists('python3.12'); const python3Version = commandVersion('python3'); - const python3NeedsPinning = - hasPython311 && hasPython312 && python3Version.includes('3.12'); + const python3NeedsPinning = hasPython312 && !python3Version.includes('3.12'); // Check for pi binary (path from env or default 'pi') const piBin = PI_TUI_BIN; @@ -257,7 +243,6 @@ export async function run(_args: string[]): Promise { const psql = getPrereq('PSQL'); const node = getPrereq('NODE'); const npm = getPrereq('NPM'); - const pillow = getPrereq('PILLOW'); const dejavuFont = getPrereq('DEJAVU_FONT'); const seatd = getPrereq('SEATD'); const weston = getPrereq('WESTON'); @@ -322,13 +307,11 @@ export async function run(_args: string[]): Promise { psql: psql.present, node: node.present, npm: npm.present, - pillow: pillow.present, dejavuFont: dejavuFont.present, seatd: seatd.present, cage: cage.present, weston: weston.present, vmBhyve: vmBhyve.present, - hasPython311, hasPython312, python3Version, python3NeedsPinning, @@ -349,7 +332,7 @@ export async function run(_args: string[]): Promise { { python3Version, }, - 'Multiple Python versions detected. Pin uv to Python 3.11 until python3 is repointed to 3.11.', + 'Python 3.12 is installed but python3 is not pinned to 3.12; use an explicit python3.12/uv pin for setup commands.', ); } @@ -381,12 +364,11 @@ export async function run(_args: string[]): Promise { PYTHON3: python3.present, PYTHON3_STATUS: python3.status, PYTHON3_INSTALL_CMD: python3.installCmd, - PYTHON311: hasPython311, PYTHON312: hasPython312, PYTHON3_VERSION: python3Version || 'unknown', UV_PYTHON_PIN_REQUIRED: python3NeedsPinning, UV_PYTHON_HINT: python3NeedsPinning - ? 'uv venv --python 3.11 && uv run --python 3.11 ' + ? 'uv venv --python 3.12 && uv run --python 3.12 ' : 'not_required', NODE: node.present, NODE_STATUS: node.status, @@ -409,9 +391,6 @@ export async function run(_args: string[]): Promise { PSQL: psql.present, PSQL_STATUS: psql.status, PSQL_INSTALL_CMD: psql.installCmd, - PILLOW: pillow.present, - PILLOW_STATUS: pillow.status, - PILLOW_INSTALL_CMD: pillow.installCmd, DEJAVU_FONT: dejavuFont.present, DEJAVU_FONT_STATUS: dejavuFont.status, DEJAVU_FONT_INSTALL_CMD: dejavuFont.installCmd, diff --git a/setup/install.ts b/setup/install.ts index 2866c66..f986827 100644 --- a/setup/install.ts +++ b/setup/install.ts @@ -408,12 +408,21 @@ function printStep( } function hasPiAuthProvider(provider: string): boolean { - const authFile = path.join(process.env.HOME || '', '.pi', 'agent', 'auth.json'); + const authFile = path.join( + process.env.HOME || '', + '.pi', + 'agent', + 'auth.json', + ); try { - const parsed = JSON.parse(fs.readFileSync(authFile, 'utf-8')) as Record; + const parsed = JSON.parse(fs.readFileSync(authFile, 'utf-8')) as Record< + string, + unknown + >; const entry = parsed?.[provider]; if (typeof entry === 'string') return entry.trim().length > 0; - if (entry && typeof entry === 'object') return Object.keys(entry).length > 0; + if (entry && typeof entry === 'object') + return Object.keys(entry).length > 0; return false; } catch { return false; @@ -460,8 +469,12 @@ function printLlmStatus(envFile: string): void { console.log( `\n ${COLS.warn}No LLM provider auth found. Configure one after install and restart:${COLS.reset}`, ); - console.log(` ${COLS.skipped} Recommended: run pi, then /login and select ChatGPT Plus/Pro (Codex).${COLS.reset}`); - console.log(` ${COLS.skipped} Or add an API key such as ANTHROPIC_API_KEY=sk-ant-...${COLS.reset}`); + console.log( + ` ${COLS.skipped} Recommended: run pi, then /login and select ChatGPT Plus/Pro (Codex).${COLS.reset}`, + ); + console.log( + ` ${COLS.skipped} Or add an API key such as ANTHROPIC_API_KEY=sk-ant-...${COLS.reset}`, + ); console.log( ` ${COLS.skipped} sudo service ${SERVICE_NAME} restart${COLS.reset}`, ); @@ -509,7 +522,7 @@ function printAiderTip(): void { ); if (!hasAider) { console.log( - ` install: ${COLS.skipped}pkg install -y py311-aider_chat${COLS.reset}`, + ` install: ${COLS.skipped}python3.12 -m venv /opt/clawdie/venv/aider && /opt/clawdie/venv/aider/bin/pip install aider-chat${COLS.reset}`, ); } console.log(` docs : ${COLS.skipped}https://aider.chat/docs/${COLS.reset}`); @@ -570,7 +583,9 @@ export async function run(argv: string[]): Promise { const opts = parseArgs(argv); const projectRoot = process.cwd(); const envFile = path.join(projectRoot, '.env'); - const envContent = fs.existsSync(envFile) ? fs.readFileSync(envFile, 'utf-8') : ''; + const envContent = fs.existsSync(envFile) + ? fs.readFileSync(envFile, 'utf-8') + : ''; if (getPlatform() !== 'freebsd') { console.error('install orchestrator is FreeBSD only.');