layered-soul/docs/TOOLCHAIN.md
Sam & Claude 2fd29cead7 docs: python 3.11/3.12 coexistence on FreeBSD; correct the Pillow rationale
Reconcile the toolchain + capability docs with clawdie-iso #84 (FreeBSD
PYTHON_DEFAULT=3.11):

- TOOLCHAIN.md: the FreeBSD column claimed `py312-*` flavors; reality is
  python312 (app) + python311 (pkg default, transitive), with py311-* prebuilt
  and py312-* absent in the quarterly repo. Added the 3.11/3.12 coexistence note
  ("3.12 floor" = floor for our code, not a ban on the base's 3.11).
- CAPABILITY-ROUTING.md: corrected the imprecise "Pillow dropped on FreeBSD"
  rationale. The blocker was the missing py312-pillow flavor, not Pillow itself;
  the prebuilt py311-pillow is available, so image-render can be restored on
  FreeBSD via 3.11. Clarified screenshot also needs a display (XFCE operator
  image yes, headless osa no → image-render only there).

prettier + layered_soul validate clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 09:44:49 +02:00

6.5 KiB

Toolchain Baseline (cross-platform)

Goal: the same frameworks and language runtimes across all hosts and OSes, so an agent relocated between Linux and FreeBSD finds an identical toolchain. Version drift is a survivability bug — if debby and OSA disagree on Python or Node, a script that works on one can silently fail on the other.

Probe before trusting this table — facts come from scripts/verify_facts_probe.py --build-tools, not memory. Update the row when you bump a host.

Baseline versions

Tool Standard Linux (Debian/Ubuntu) FreeBSD 15 (pkg) Manager / source
Python 3.12 (floor) python3.13 (debby) — ≥ floor python312 (app) + python311 (pkg default, transitive); py311-* flavors prebuilt, py312-* absent in quarterly system pkg + uv for venvs
uv ≥ 0.11 uv 0.11.21 uv (pkg) — confirm standalone binary
Node 24 LTS (target) fnm → v24.16.0 (debby) node24 + npm-node24 fnm (Rust, cross-platform)
Rust stable (pinned) rustup 1.95.0 rust (pkg) rust-toolchain.toml per repo
Go latest stable go 1.24.4 (debby) go (pkg) only where a Go component exists
Zig 0.15.2 ~/.local/bin/zig manual pinned (herdr build dep)
tmux latest stable tmux tmux system pkg

Conventions

Python — never pin the version in a shebang

  • Scripts use #!/usr/bin/env python3. No python3.11 / python3.12 shebangs.
  • The interpreter is selected by a symlink provided at image/host setup time, so a future bump (3.12 → 3.13) is a one-line change in one place, not a sweep across scripts.
  • FreeBSD ISO build provides the symlink (FreeBSD pkg ships python3.12 but no bare python3):
    # in clawdie-iso build.sh, version-agnostic:
    py_bin=$(ls "${MOUNT_POINT}/usr/local/bin"/python3.* 2>/dev/null \
      | sed 's@.*/@@' | grep -E '^python3\.[0-9]+$' | sort -V | tail -1)
    ln -sf "${py_bin}" "${MOUNT_POINT}/usr/local/bin/python3"
    ln -sf "${py_bin}" "${MOUNT_POINT}/usr/local/bin/python"
    
  • venv creation calls python3 -m venv (resolves via the symlink) — not python3.12 -m venv.
  • uv is the standard venv/dependency manager across all OSes. Prefer uv venv / uv pip / uv sync over raw python -m venv + pip so resolution and lockfiles match everywhere. uv itself is interpreter-agnostic and picks up whatever python3 resolves to.

Node — LTS only, one major across the matrix

  • Standard target: Node 24 LTS (FreeBSD already ships node24; npm 11).
  • Resolved 2026-06-17: debby switched to Node 24 via fnm (system Node 20 remains for OS-level tools, but all Clawdie/agent workloads use 24). FreeBSD already on 24. One step remains: bump the Hermes Dockerfile node_source:2224 to match.
  • package.json engines floor stays generous (>=20) but installed runtime tracks the agreed LTS. Never run a non-LTS Node major in production.

Rust / Go / Zig

  • Rust: pin per-repo with rust-toolchain.toml (channel stable) so FreeBSD pkg rust and Linux rustup resolve the same toolchain. TLS via rustls (no openssl-sys) for the x86_64-unknown-freebsd Tier-2 target.
  • Go: only where a Go component exists; track latest stable.
  • Zig pinned at 0.15.2 (herdr); bump deliberately.

Managed tools (tmux, codex, pi, zot, …)

  • These are agent/utility tools, not language runtimes. Track latest stable from the platform package manager; record notable pins here when they matter.
  • Pi is being retired (see consolidation on zot + Colibri). Codex stays (osa, ISO builds).

Python 3.12 standardization (decision, 2026-06-17)

Consensus of operator + Hermes + Claude. Standardize on Python 3.12 floor everywhere.

  • Rationale: available on Debian 13 and FreeBSD 15 via pkg; has needed stdlib (zoneinfo, match/case); avoids 3.13 bleeding-edge quirks. Unifies a stack that was drifting (debby Docker 3.13, domedog 3.12, OSA 3.11).
  • No code blocker: hermes-bsd/pyproject.toml already allows >=3.11,<3.14; Hermes scripts use env python3.
  • FreeBSD 3.11/3.12 coexistence (clawdie-iso #84): FreeBSD's PYTHON_DEFAULT is 3.11, so system pkgs (git, libinput, npm-node24, …) pull python311 transitively. python312 is the application Python and wins the python3 symlink via sort -V. Both coexist intentionally — "3.12 floor" is the floor for our code, not a ban on the 3.11 the base drags in.
  • FreeBSD packaging reality: OSA's quarterly repo publishes python312, but not the matching py312-aider_chat, py312-pillow, py312-pip, or py312-pygobject flavors yet — only the default-flavor py311-* are prebuilt. Keep py312-* extras out of pkg-list-*.txt until they exist; install those into explicit 3.12 venvs with uv/pip when needed. Exception worth noting: for Pillow, the prebuilt py311-pillow is available, so image-render can run on the already-present 3.11 instead of compiling Pillow into a 3.12 venv (see CAPABILITY-ROUTING.md).
  • ISO direction: clawdie-iso should carry python312, version-agnostic python3 symlinks in build.sh, and python3 -m venv calls. Drop packages such as gnumeric when they keep the old Python flavor alive transitively.

See AGENTS.md for the agent matrix and HOST-MATRIX.md for per-host hardware facts.