Repository navigation
Releases: EstebanForge/construct-cli
Releases · EstebanForge/construct-cli
Release list
The Construct CLI 1.17.19
[1.17.19] - 2026-10-01
Fixed
constructnow verifies the host msb runtime before every microVM launch and says exactly what to fix when it cannot pair. The embedded microsandbox SDK refuses any host runtime except its own exact version with the crypticno tested sandbox launch contracterror — and since the 1.17.17 SDK bump embedded 0.7.3, a version no msb release ever shipped, every machine with any other msb failed at daemon create, often after pulling the image first. Both create entry points now fail fast before image acquisition, naming both versions and the side to update (msb updateorct sys self-update); 1.x hosts are refused as untested. The policy is shared with doctor's Host CLI/SDK Skew check (match OK, 0.x mismatch warning, 1.x error), which now reads the SDK version from the SDK itself instead of a hand-maintained constant that had silently drifted.- Embedded the 0.7.6 SDK, matching the current msb release, so version-matched hosts launch again.
The Construct CLI 1.17.18
[1.17.18] - 2026-10-01
Fixed
- The microVM sandbox boots on the image ref the acquisition step verified. Image acquisition and sandbox creation resolved the boot image independently: acquisition verified the freshly pulled GHCR ref, but the create-time candidate walk could hand msb a listed-but-unusable legacy bare
construct-box:latestentry instead, which msb then resolved at docker.io —registry error: Not authorizedon every boot despite a fresh image, exactly what 1.17.17 upgraders hit after the migration wiped and re-pulled the cache. EnsureImage now returns the ref it verified on every path (local build, cached GHCR, fresh pull, pull-failure fallback), and the daemon and agent-install specs boot that ref directly; candidate resolution survives only as a fallback when no ref was threaded. sys doctor --fixnow recovers a still-starting msb daemon. The VM Backend check probed the daemon once and failed closed, while the same run's Baked Image pull auto-started the daemon two checks later and reported success — an incoherent report with no fix attempt, since msb starts its daemon on demand and a probe right after a crash can lose that race. Under --fix the check now retries bounded (3 attempts, 2 seconds apart) before declaring the backend broken and reports the recovery; a crash-looping daemon still fails with the existing suggestion, and plain doctor stays report-only.
The Construct CLI 1.17.17
[1.17.17] - 2026-10-01
Added
- Agents pre-installed on the image can now update themselves in-guest. The image chowns the agent tier to the runtime user (
/usr/local/lib/node_modules, the bin directory, and the baked binaries), so self-updaters likepi update --all,claude update, andcodex updatewrite their install prefix in place instead of failing on root-owned paths, while the system toolchain and entrypoint scripts stay image-owned and the image lane stays authoritative — a root-fs replace on image pull still reaches every machine./usr/local/bincarries the sticky bit, so the runtime user can replace its own agent symlinks but cannot remove the root-owned entrypoint scripts the next boot runs as root. pinow updates its extensions, models, and self inside the guest update routine. update-all.sh runspi update --no-approve --models, and when the baked binary is user-writable alsopi update --no-approve --all(self + extensions); on older images with a still-root-owned binary, self-update is skipped with a note while user-tier extensions and models still refresh.--no-approvekeeps the non-interactive run from trusting project-local files.sys updatewarns that in-VM updates revert on daemon recreate. Agent and OS package updates live in the VM's writable layer, which a daemon recreate (image update or config change) replaces: a successful foreground update now says so and reminds to runconstruct sys updateagain afterwards, and the recreate banner repeats the reminder at the moment the revert happens. On the compose backend the wording differs on purpose — its update runs in a throwaway--rmcontainer, so agent and OS updates there are discarded on exit and only home-directory updates persist.
Fixed
- Agent self-updates keep working on hosts whose uid is not 1000. The build-time chown hardcodes the image default (1000:1000) while
ExecAsHostUserremaps the runtime user to the host uid on every non-1000 host, and the entrypoint re-chowned only the home tree, so the remapped user lost write access exactly where remapping is enabled. The remap branch now re-aligns the agent tier to the remapped id, probed so the recursive chown only pays when the numeric id actually changed.
The Construct CLI 1.17.16
[1.17.16] - 2026-10-01
Fixed
sys updateno longer fails on topgrade's built-in pi step. topgrade 17.4.0 shipped a built-inpistep that runspi update --self, and the image pins topgrade 17.7.0, so every in-guest update ran it against the baked root-owned/usr/local/bin/pi: pi refuses to self-update an npm-managed install on an unwritable path, the step fails, and topgrade exits 1, failing the whole pass. The run log naming the steppi(a[commands]entry would be named by its TOML key,Pi Coding Agent) proved the culprit was topgrade's binary detection, not the stale-config theory behind 1.17.14's derived-file refresh. The step is now disabled likeclaude_code(baked agents update on the image lane, never in-guest) in the shipped template, the generator, and the no-config fallback, with a test pinning the generated list. The disable list only carries step keys that exist in the pinned topgrade: an unknown key makes its config loader fall back to an empty default config and silently drop every other disable rule.- The host-exec shim no longer drops stdin that arrives late. The shim gated piped input on a single non-blocking peek, so a parent whose pipe write landed after shim startup shipped an empty stdin silently: a loaded CI runner hit exactly this on the 1.17.15 tag run, and any real-world writer slower than shim startup could too. The peek stays, keeping open-empty launcher pipes free of the 5s read budget, but it now polls across a 300ms grace window before concluding the pipe is empty, and a regression test writes stdin 100ms after start to pin the behavior.
The Construct CLI 1.17.14
[1.17.14] - 2026-09-30
Fixed
- The microVM update no longer fails on a stale home topgrade.toml. msb reads topgrade.toml straight from the persistent home volume, and the update paths refreshed only the four mounted helper scripts, so the pre-1.17.0
[commands]pi self-update entry survived there: topgrade kept executing it against the baked root-owned/usr/local/bin/pi, the write failed, and one stale file failed the whole update pass. Both update paths now rewrite install_user_packages.sh and topgrade.toml from the current packages.toml before update-all.sh runs; an unreadable packages.toml skips the idle window and fails the foreground run, write failures still warn and continue, and the msb home copy of the install script stays owned by the daemon-start regeneration. sys doctorreports the last failed update. The update-log check green-lit any readable log, so a run ending inupdate failedlooked clean. It now parses the updater's log markers (anchored on the RFC3339 prefix, so tool output tee'd into the log cannot fake a run boundary), warns with the failed step names from the newest failed run, and points atconstruct sys updateto retry.sys doctorstops probing the docker API on microvm hosts. The stale-packages-volume check ran an OCI daemon probe even withbackend = microvmand printed raw socket errors on hosts that opted out of container engines entirely. It now reports "Not applicable (runtime backend = microvm)" without probing.- Failure suggestions name a real command. Seven error paths told users to run
construct doctor(never registered; the verb isconstruct sys doctor) and HOST-EXEC.md pointed atconstruct build(the verb isconstruct sys rebuild). All corrected.
The Construct CLI 1.17.13
[1.17.13] - 2026-09-28
Fixed
- The microVM engine no longer boots a stale construct-box image after an image-tier template change. Three defects chained into a loop with no exit while the registry answered: msb caches a GHCR pull under the full ghcr.io ref (no tag aliasing) but the migration teardown removed only the bare local name, image acquisition pulled GitHub first and consulted the local docker store only when the pull failed, and the digest drift check compared a deliberately built localhost ref against the CI manifest digest, a comparison a local build can never win even at identical content. Together that meant
construct sys rebuildcomposed an image nothing consumed and the sandbox kept booting the stale published image on every run. The cached-ref preference list now puts the localhost build first for both the boot image and the daemon digest label, the drift check compares the registry ref's own digest so local refs can never false-drift into a per-run re-download,sys rebuildandsys initon the microvm backend transition the fresh build into the msb cache, and the teardown removes all three cached ref forms. Migration completion notes and help text describe the real flow: both engines re-pull from GitHub Container Registry, and a local build happens only throughconstruct sys rebuildor as the pull-failure fallback.
The Construct CLI 1.17.12
Full changelog: 1.17.11...1.17.12
The Construct CLI 1.17.11
[1.17.11] - 2026-09-28
Fixed
- Stale shipped defaults in config.toml are reset on update and by
sys doctor --fix. The update migration replaced container templates and merged packages.toml but never rewrote config.toml, so an old shipped default survived forever disguised as a user value: a real user'sworkspace_max_entries = 60000from an older template kept the large-workspace warning firing long after the ceiling rose to 500000, and a stale daemon restart could not fix it because the value lives host-side in the config file, not in daemon state. Values that exactly match a stale shipped default are now rewritten in place with inline comments and spacing preserved; anything else (a deliberately chosen 75000, other sections, commented lines) is untouched, and the rewrite is idempotent. One rewrite path serves both the update migration andconstruct sys doctor --fix(which warns without the flag, naming the exactkey old → newfinding), so the two can never diverge, and future default bumps are one row in a table. The guard's fallback budget and the template's shipped default are now asserted equal by a test: the template writes the former while the guard falls back to the latter when the key is unset, so drift between them would make "unset" and "freshly written" behave differently.
The Construct CLI 1.17.10
[1.17.10] - 2026-09-27
Added
- Pig joins the supported agent roster. Pig, the Go implementation of pi (pi-in-go.dev), is now a default supported agent:
construct pigmounts~/.piginto the sandbox,sys agents-mdwrites its rules to~/.pig/agent/AGENTS.md, harness path-argument staging covers--extensionand--session(pig 0.2.0 has no--mcp-configflag), both update verification loops check the binary, and first-run setup seeds~/.pig/agent/auth.jsonlike pi's. The binary is baked into construct-box at /usr/local/bin and pinned: pi-in-go.dev 403s GitHub Actions runner egress, so the image build fetches the installer from the PiG repository on GitHub and pins PIG_VERSION=0.2.0. Pig reads~/.agents/skillsnatively, keeps its whole config under~/.pig, and never touches pi's~/.pi; existing sandboxes pick the new image up through the image-digest recreate check.
Fixed
sys agents-mdnow writes pi's rules file. Pi has shipped in the image and the agent registry for several releases, but it was missing from the rules distribution list, so~/.pi/agent/AGENTS.mdwas never written inside the sandbox. It is registered alongside pig, which closes the gap for both.
The Construct CLI 1.17.9
[1.17.9] - 2026-09-25
Changed
- The large-workspace warning is asked once per folder, not forever. Runs from a folder over the entry budget printed the warning and confirmed every single time; the Yes went nowhere. Acceptance now persists per folder (subdirectories included), so the first run asks and later runs skip the guard entirely - no scan, no warning, no confirm. A No still persists nothing, headless runs still fail closed, the home directory can never be accepted (the always-ask home warning stays),
roots forgetclears an acceptance, androots listshows accepted folders. The entry budget also rises from 60000 to 500000: one modern JavaScript project alone carries 50-150k files, and the old ceiling predated both that reality and current virtiofs performance. The scan's time budget doubles to 3s so timeouts do not shadow the count. construct sys daemon recreategives the wipe-and-rebuild a first-class verb. The stale-image heal previously required rawmsb rm construct-cli-daemon. Recreate stops the sandbox, removes it with its guest root disk, and cold-creates from the current image - under the daemon flock, refusing while live sessions exist, with a default-NO confirm and a warning that installed tools reinstall on the next boot. The home volume is a host bind, so user-level state survives.- A republished construct-box now reaches running daemons. A new
construct.daemon.image_digestlabel records the digest a sandbox was created from; when the local image digest drifts (because the digest-refresh fix pulled a newer one), the daemon recreates exactly once with reason "construct-box image changed". Daemons predating the label upgrade the same way, and an unknown local digest never forces a recreate.
Fixed
- Image refresh no longer false-drifts on every create. 1.17.8 compared the registry's multi-arch index digest against the platform manifest digest the image store actually caches - different layers of the manifest tree that never match - so every create re-downloaded the image, on Apple Silicon hosts too. The refresh now resolves the index down to the linux/ entry, which is what the store caches on both Intel and Apple Silicon hosts, and treats any resolution failure as "keep the cached image" instead of "download again".
- The recreate decision can no longer be silently skipped. When the sandbox's stored config cannot be read (an msb record predating config persistence, or a corrupted one), every label-drift check was invisible behind a healthy-looking reconnect. The decision now prints a loud warning naming
construct sys daemon recreateas the recovery. - The one-shot install sandbox no longer lingers. The first-run agent install ran in a dedicated sandbox that stayed behind as a stopped record forever, pinning the construct-box image and blocking image cleanup. It is now removed right after a successful install.
- npm global reinstalls no longer fail with ENOTEMPTY. Interrupted npm runs leave dot-prefixed temp dirs under the global node_modules, npm never cleans them up, and every later install of the affected package fails renaming onto the occupied destination. The update script sweeps them before the reinstall loop, sparing .bin and keeping broken symlinks from stopping the sweep.