feat: install the latest release of every tool on each apply - #22
Merged
Merged
Conversation
…s; drop codex and pnpm Every apply now resolves the newest release of node (nodejs.org index, not LTS), bun, gh, no-mistakes and treehouse, verified against the SHA-256 the publisher lists for that release (GitHub release-asset digest, or Node's SHASUMS256.txt), and the npm registry's latest chrome-devtools-axi, gh-axi, lavish-axi, quota-axi and tasks-axi, each in its own versioned prefix like omp. Only uv, rustup-init and the Rust toolchain stay pinned in the lock. codex and pnpm leave the npm set; acpx defaults to omp, and the installer unlinks commands whose managed package is gone.
The worktree seeder now writes a git-excluded .env.fleet with the node heap cap, and the managed shell and Herdr environment set BUN_OPTIONS=--env-file=.env.fleet under fleet guards, so every bun started in a worktree root (bun run dev, omp) hands NODE_OPTIONS to the node processes it spawns. pnpm is gone from the reaper chain and the docs.
… checksums Nothing the recipe installs is pinned any more. uv, rustup-init, Obscura, acpx and chrome-devtools-mcp join the latest-resolution path; the Rust toolchain follows stable; psutil is the latest PyPI release installed with --require-hashes against PyPI's digests; the Supabase CLI is the registry's latest; the worker image builds FROM ubuntu:latest. Every download is still verified against the checksum its publisher posts for that release. toolchain.lock.json, its schema, tools/npm, maintenance/requirements.txt, the shared-supabase package lock and the obscura config keys are gone. Apply also installs and upgrades the ponytail, i-have-adhd and caveman omp plugins. uv.lock and the SHA-pinned GitHub Actions stay.
… the pins astral-sh/setup-uv moves to v10.2.0; actions/checkout v7.0.1 and oven-sh/setup-bun v2.2.0 are already their latest releases. A weekly github-actions Dependabot update keeps the SHA pins on the newest release.
…eption docs; fix validate row
…heap cap to lanes
…heap cap, smoke checks plugin record
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
"update all pinned to no mistakes, node, bun, gh, treehouse, and all axi tools to check and install latest, the rest i do not use so throw it away"
Context for reading that ask: Code-Factory today pins most of its toolchain. Native tools (node, bun, uv, gh, no-mistakes, treehouse, rustup-init, plus the rust toolchain) carry exact versions and per-architecture SHA-256 hashes in
toolchain.lock.json. The npm tools (pi, codex, pnpm, and the axi family: chrome-devtools-axi, gh-axi, lavish-axi, quota-axi, tasks-axi) carry exact versions intools/npm/package.jsonandtools/npm/package-lock.json. Only herdr and omp are already resolved to their latest release on every apply (docs/architecture.md"update" steps 1 and 2,scripts/install_tools.pyresolve_latest). The list the request was answering was: no-mistakes, node, bun, gh, treehouse, codex, pi, pnpm, and the axi tools. So "latest" covers no-mistakes, node, bun, gh, treehouse, and the five axi tools, and "the rest ... throw it away" covers codex, pi, and pnpm.On pnpm, which the fleet-guard worktree tooling used for
pnpm dev: "update to use latest bun only and drop it" - pnpm is dropped completely, and bun, installed at its latest release on every apply, is the single package manager and runner the recipe relies on, so anything Code-Factory ran through pnpm runs through bun instead. Node stays."make sure stuff is not pinned and instead is latest" - everything Code-Factory installs resolves to its latest release on every apply, including uv, rustup-init, the Rust toolchain (the stable channel), the Obscura browser binary, the Chrome pruner's psutil, the shared Supabase CLI, the Docker worker base image (
ubuntu:latest), and the omp marketplace plugins the recipe uses (installed and upgraded to latest on every apply). Every download is still verified against the checksum or digest its publisher posts for that exact release, and a release without one is refused. Code-Factory's ownuv.lockdevelopment environment stays locked."ci: pin latest" - in
.github/workflows, every GitHub Action stays pinned to a full commit SHA, moved to the SHA of that action's latest release tag with the tag in a trailing comment, and.github/dependabot.ymladds a weeklygithub-actionsupdate so the pins keep moving to the newest release.What Changed
scripts/install_tools.pynow resolves every tool it installs to its latest release on each apply: node, bun, gh, uv, no-mistakes, treehouse, rustup-init, the Rust stable toolchain, the axi npm tools, Obscura, the Supabase CLI and the Chrome pruner's psutil. Each download is checked against the checksum, digest or npm integrity its publisher posts for that release. A release with no published checksum is refused. The omp marketplace plugins are installed and upgraded to their default branch instead. codex, pi and pnpm are dropped, and the acpx default agent is switched from codex to omp. Removed:toolchain.lock.json,schemas/toolchain.schema.json, thetools/npmandfleet/shared-supabasepackage files, andmaintenance/requirements.txt. The Ansible tasks, templates, config and docs are updated to match, and the Obscura version and SHA keys in the factory schema are marked deprecated and no longer required.worktree-env-seed.shwrites a heap-cappingnodewrapper into each pool slot instead of a per-worktree.npmrc.chrome-autoprune.pyrecognises per-versionchrome-devtools-axiinstall prefixes as well as the retired shared npm prefix.ubuntu:latest, with the digest pin removed. In CI, uv and Bun install at latest, and each action is pinned to the commit SHA of its latest release..github/dependabot.ymladds a weeklygithub-actionsupdate. Tests are updated for the new installer behaviour, and new tests cover the Chrome pruner and the worktree env seeder.Risk Assessment
🚨 High: The host-wide
BUN_OPTIONS=--env-file=.env.fleetsilently stops every bun process from loading.envand.env.local, including the Supabase env the fleet seeds into worktrees. Bootstrap also now depends on unauthenticated multi-source resolution, which is a likely image-build failure. Two intent gaps (legacy codex/pnpm survive upgrades, unverified omp plugins) need author decisions.Testing
I ran the real installer in a scratch HOME from a checkout under ~ Every native and axi tool resolved to the latest upstream release and installed with its checksum verified. The retired tools were removed correctly, tampered or unsafe inputs were refused, and the omp plugins landed in the target home while the real ~/.omp record stayed untouched. Separately I leased a fresh treehouse lane and confirmed the first bun/npx dev server reports the capped 2144 MB heap; the plain shell node stays at 4192 MB. The Herdr unit render, Obscura, psutil and Supabase, config validation, CI pins and a 21/21 container smoke also passed, plus 78 targeted pytest cases. Not exercised: a hosted GitHub Actions run and Dependabot opening PRs.
npm view: chrome-devtools-axi 0.1.36, gh-axi 0.1.35, lavish-axi 0.1.80, quota-axi 0.1.55, tasks-axi 0.2.6, omp 18.4.6, acpx 0.19.4, chrome-devtools-mcp 1.10.1currentlink and leaves the managed MCP path and the Herdr unit text unchanged, so Herdr does not restart; a Herdr upgrade still changes the un…bun run devis heap-capped: the seeder writes the slot-level node wrapper beforebun install, the cap survivesrm -rf node_modules, the override works, and a plain…bun installthe slot holds the wrapper; the firstbun run devandnpxreport heap_limit_mb=2144 and execArgv --max-old-space-size=2048;…Evidence: Container smoke on ubuntu:latest, 21/21 checks, exit 0
Evidence: Live install run 1 (changed=true) and run 2 (changed=false)
Evidence: Installed versions, retirement outcome, MCP current link and omp plugin record
Evidence: Upstream latest GitHub tags for the native tools
Evidence: Refusals: tampered SHA, empty SHA, http URL, unsafe version, plus the control run
Evidence: Fresh treehouse lane: seeder, bun install, bun run dev capped at 2144 MB
Evidence: Rust stable toolchain and installer-driven MCP release bump with a stable current link
Evidence: Herdr unit text identical across MCP releases, changes on a Herdr upgrade
Evidence: psutil hash-verified install and Supabase CLI latest
Evidence: Obscura latest asset digest match
Evidence: Config validation: default, legacy obscura pins, malformed sha
Evidence: CI action pins versus latest releases, and Dependabot config
Evidence: Targeted pytest, 78 passed
Pipeline
Updates from git push no-mistakes
... (106 earlier update rounds omitted to keep the PR body within GitHub's 65536-char limit; full history is in the run log.)
The pin has a stated safety reason. A floating Postgres tag would move a data volume across major versions it cannot read. CI also enforces the pin at
.github/workflows/ci.yml:230.No change is needed. If the author wants these floating too, that is a separate decision. It would also mean removing the CI digest audit and the docs exception.
bootstrap.sh:9- Judged after the advisory. The behavior change is real, but it is not a new failure of a flow that worked before, so no action is needed.What changed: line 9 now always runs
install_tools.py --tools uv. An unmanaged regular file at~/.local/bin/uv, such as an Astral standalone install orpip --user, makeslink_binaryraiseunmanaged command exists.set -ethen aborts the bootstrap. Only stdout is discarded, so the error still shows on stderr. The base skipped the installer whenuv --versionmatched the lock pin, which was uv 0.12.5.Why it does not hold as a regression:
link_binaryis identical to head, so any version mismatch already hit the same error. Standalone uv installs track the newest release, so only hosts on exactly 0.12.5 got through bootstrap.factory_core_toolsis[herdr, node, bun, uv]in base and head../factory applyrunsinstall_asset('uv')and then the samelink_binaryraise.docs/configuration.mdstates the recipe refuses to overwrite unmanaged commands. Head moves the failure earlier and keeps the same actionable message.The one narrow loss is a contributor on exactly uv 0.12.5 who used bootstrap only to build the dev venv. Keeping the old skip would contradict the intent's latest-uv requirement and README step 3, 'the latest uv'. The intent-driven cost is that bootstrap now makes a GitHub API call on every run.
docs/dependencies.mddocuments the rate limit and theGITHUB_TOKENoption.🔧 **Test** - 3 issues found → auto-fixed ✅
scripts/install_tools.py:465-omp_pluginsrunsomp plugin ...with nocwd, so the plugin step depends on the directory the installer starts in.ansible/tasks/tools.ymlruns the installer withchdir: code_factory_repoandbecome_user: factory_cfg.user. If the checkout sits under another user's tree that has its own.omp,omp plugin listreports that tree's records as already installed. Reproduced live with--tools node,bun --npm(omp-plugins-cwd-dependence.txt):--homewas a scratch HOME and cwd was a checkout under~, which has.omp. The installer exited 0, but the target HOME had no~/.omp/plugins/installed_plugins.json.omp plugin listprinted ponytail, i-have-adhd and caveman from~/.omp, soomp installwas skipped. With cwd set to--home, the list was empty and all three plugins installed. The real~/.omprecord was not modified. The container smoke passed because/opt/code-factoryhas no.ompancestor, and a checkout under the target user's own home is also unaffected. Fix: passcwd=hometo thesubprocess.runin the nestedomp()helper.rm -rf /tmp/cf-*.json /tmp/cf-*.yml /tmp/cf-req*.txt. Those globs could have matched/tmp/cf-*files that other sessions created, and I cannot tell afterwards whether any existed. Files with other extensions (.toml,.txt,.patch,.log,.out,.body,.intent) and directories were not matched by the globs and are still there. If another session reports a missing/tmp/cf-*.jsonor/tmp/cf-*.yml, this is the likely cause. Nothing in the worktree or the evidence directory was affected.currentlink: a release bump re-points the link, the exported path and Herdr unit text do not change, the old release stays on disk./factory applyon a host withstart_servicesenabled, create a new treehouse…./factory apply, and the behavior smoke passes with the second apply idempotentpython3 scripts/install_tools.py --resolvefor every source against live GitHub, npm, nodejs.org, PyPI and rust-langinstall_tools.py --npminto a scratch HOME: run 1 with older chrome-devtools-mcp 1.9.0, run 2 live latest, run 3 no-opinstall_tools.py --tools bun --developmentinto the scratch HOME, plus a no-op second runAdversarial--resolvedruns: wrong sha256 for bun, and unsafe gh-axi version1.0.0/../../evilLegacy npm prefix pre-seeded with codex and pnpm links plus a pnpx link elsewhere, then retired by the installerReal treehouse v3.1.0 lane withfleet/doctor/worktree-env-seed.shrun by hand after the lane was created:bun install,bun run dev,bun run probe,npx,rm -rf node_modules,FLEET_NODE_HEAP_MB=1024, return and re-lease of slot 1,treehouse destroy --all --yesA second newly leased slot (slot 2) with no seeder run, to see what an unseeded slot getsnodelaunching the chrome-devtools-mcp entrypoint through thecurrentpath at 1.10.1 and 1.9.0;chrome-devtools-axi --helpwithCHROME_DEVTOOLS_AXI_MCP_PATHsetansible/templates/herdr.service.j2rendered with real Jinja2 againstansible/group_vars/all.ymlfor mcp 1.9.0, mcp 1.10.1 and a Herdr bumpThe exactjqassertion fromtests/container-smoke.shagainst the real ompinstalled_plugins.json, plus a never-installed plugin and a marketplace-only plugininstall_tools.py --tools node,bun --npm --resolved ...run from a checkout cwd under ~ (which has.omp) and again from cwd=--home, thenomp plugin list --jsonfrom each cwd./factory validateon the default config, a legacy config with obscura pins, a malformed legacy sha, and a fleet_guards config with no pinsCI pins: everyuses:in.github/workflows/ci.ymlcompared with the GitHub API latest release tag and commit SHA;.github/dependabot.ymlparsedObscura latest asset sha256 compared with the publisher digest; psutiluv pip install --require-hashes(good and bad digest);npm install supabase@2.119.0uv run --frozen pytest tests/test_configuration.py tests/test_install_tools.py tests/test_worktree_env_seed.py tests/test_chrome_autoprune.py(77 passed)CF_SMOKE_MEMORY=6g CF_SMOKE_CPUS=2 tests/container-smoke.sh(docker build of the smoke target on ubuntu:latest, then 21 in-container checks)🔧 Fix applied.
✅ Re-checked - no issues remain.
npm view: chrome-devtools-axi 0.1.36, gh-axi 0.1.35, lavish-axi 0.1.80, quota-axi 0.1.55, tasks-axi 0.2.6, omp 18.4.6, acpx 0.19.4, chrome-devtools-mcp 1.10.1currentlink and leaves the managed MCP path and the Herdr unit text unchanged, so Herdr does not restart; a Herdr upgrade still changes the un…bun run devis heap-capped: the seeder writes the slot-level node wrapper beforebun install, the cap survivesrm -rf node_modules, the override works, and a plain…bun installthe slot holds the wrapper; the firstbun run devandnpxreport heap_limit_mb=2144 and execArgv --max-old-space-size=2048;…python3 scripts/install_tools.py --home /tmp/cf-scratch-home --tools herdr,node,bun,uv --npm --development, run from the worktree under ~ (which has its own .omp), against a scratch home seeded with legacy codex/pnpm/pnpx linksSecond identical installer run: changed=falseVersion check of every installed command against the registry or GitHub latest:npm viewfor the axi tools, omp, acpx and chrome-devtools-mcp; nodejs.org/dist/index.json; GitHub releases/latest for herdr, bun, gh, no-mistakes, treehouse and uv; rustup's release-stable.tomlRetirement check in the scratch home: codex and pnpx links removed, a pnpm link pointing elsewhere kept, legacynpm/directory keptAdversarial--resolvedruns: wrong SHA-256 on the real bun 1.4.2 asset, empty SHA-256, http:// URL, and an unsafe npm version../../evilInstaller-driven chrome-devtools-mcp bump (1.9.0 to 1.10.1) checking the stablecurrentlink, plus a real Ansible render ofansible/templates/herdr.service.j2for two MCP releases and for a Herdr upgradeFresh treehouse lane (treehouse get --lease) with the realfleet/doctor/worktree-env-seed.sh, thenbun install,bun run devandnpx. The check also re-measured whether bun passes.env.localNODE_OPTIONS (it does not on 1.4.2),rm -rf node_modules, the seeder's second-run idempotence, and the FLEET_NODE_HEAP_MB override--resolve --also obscura,psutil,supabase: Obscura asset downloaded and compared with the publisher digest, psutil installed with uv--require-hashes(a wrong digest is refused), Supabase CLI installed from npm at the resolved version./factory validateon config/default.yml, on a legacy document carrying obscura pins (accepted with a warning), and on one with a malformed obscura sha (rejected)CI workflow pins: alluses:are 40-char SHAs with tag comments, and each equals the commit of the action's latest GitHub release (git ls-remoteplus releases/latest);.github/dependabot.ymlparsed for a weekly github-actions updatetests/container-smoke.sh: full image build onubuntu:latest, 21/21 checks, including resolved-releases, installer-idempotent and ansible-second-pass.venv/bin/python -m pytest tests/test_configuration.py tests/test_install_tools.py tests/test_worktree_env_seed.py tests/test_chrome_autoprune.py -v: 78 passedConfirmed the real ~/.omp/plugins/installed_plugins.json md5 was unchanged after the installer runsdocs/configuration.md:79- Thedevelopmentprofile row still lists "development-mode npm packages".--developmentonly runsrust_install, and apt supplies the build packages. The base commit already behaved this way, so this change did not make the row stale and I left it. A follow-up could reword the row to "Rust toolchain, build essentials".ansible/tasks/tools.yml:100- The Ansible taskname:"Assert the managed symlink resolves to the locked executable" still says "locked", but the herdr executable is now the resolved latest release. This is a task name that shows in plan/apply output, not a doc comment, so it is outside this phase's edit rule and I did not rename it. Herdr was already resolved to latest before this change, so the wording was not newly made stale. A follow-up could rename it to "resolved executable". No test references the string.🔧 Fix applied.
1 info still open:
CONTRIBUTING.md:46- CONTRIBUTING.md tells contributors to run./scripts/ci-local.sh, but that file does not exist. It was also missing at the base commit, so this change did not cause it and I left the line alone. A follow-up could drop the line or add the script.✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.