feat(release): publish a generic all-in-one stack image - #506
Merged
Conversation
The release stack was the inverse of what it is published for: no `INSTALL_AI_CLIENTS` line at all, so `engine/Dockerfile`'s `false` default won, and `INSTALL_CADASTRE_MCP=true`. It shipped the maintainer's estate MCP to strangers while withholding the two CLIs the product exists to run. Nothing was red, because nothing asserted either half. A release now builds the generic shape — claude and codex, no estate integrations, the `lean` pod base — and `deploy/stack.compose.yml` runs it with only an `.env`. `build.yml`'s dev/prod branch builds keep the estate rule and layer cadastre and theclawbay on top of the same base, which is the parity model stated one level up from `engine/Dockerfile`'s "the private path is the public path plus configuration". `vogt-verify-agent-clis` does not prove the CLIs are present and never did. It is a shadow detector: `check_tool` returns 0 when the system path does not exist, `check_package` returns 0 unless the binary is executable, and `agent-versions.resolved` is written unconditionally, so it is green on a CLI-free image. The release smoke test now runs `claude` and `codex`, which is the only thing separating a generic release from a silent reversion to the CLI-free one (#23). Also #505: the pin moves 2.1.236 -> 2.1.258, since Claude Fable 5.1 arrived in 2.1.257 and the pin is deliberately unwalkable at runtime (#196), so a stale one can only be fixed by a rebuild. `npm install -g` exiting 0 is not evidence that `claude` runs — the tarball ships `bin/claude.exe` as a stub resolved by `postinstall` — so the build now runs it against the pin. That is the packaging that broke 2.1.237 (#147/#148) and held the pin for months. `#` inside a `build-args: |` block is content, not a comment, and reaches buildx as a build arg. `build.yml` already carried a note saying so because the mistake had been made once; it was made again here, so it is now a test over both workflows instead of a comment in one. Docs: DEPLOYMENT §1.1 compares the three shapes and states the AIO's dev-pod posture plainly (sudo, sshd, DooD, no `read_only`); §7 replaces the "CLI-free by design" claim with the generic-vs-estate tag table; CUSTOMISATION gains the `FROM vogt-stack@sha256:...` worked example that is how the private overlays are actually built. Four sites said "no engine image is published", which was true of the engine alone and is now stated that way. Refs #505
thedancingdeveloper
force-pushed
the
feat/generic-aio
branch
from
September 2, 2026 02:29
b117ff4 to
92e9aec
Compare
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.
The release stack was the inverse of what it is published for: no
INSTALL_AI_CLIENTSline at all, soengine/Dockerfile'sfalsedefault won, andINSTALL_CADASTRE_MCP=true. It shipped the maintainer's estate MCP to strangers while withholding the two CLIs the product exists to run. Nothing was red, because nothing asserted either half.A release now builds the generic shape —
claudeandcodex, no estate integrations, theleanpod base — anddeploy/stack.compose.ymlruns it with only an.env.build.yml's dev/prod branch builds keep the estate rule and layer Cadastre and theclawbay on top of the same base, which is the parity model stated one level up fromengine/Dockerfile's "the private path is the public path plus configuration".The verification that did not exist
vogt-verify-agent-clisdoes not prove the CLIs are present and never did. It is a shadow detector:check_toolreturns 0 when the system path does not exist,check_packagereturns 0 unless the binary is executable, andagent-versions.resolvedis written unconditionally — so it is green on a CLI-free image. It answers "is a persisted$HOMEcopy shadowing the image's?", not "is there an image copy?".The release smoke test now runs
claudeandcodex. That is the only thing separating a generic release from a silent reversion to the CLI-free one (#23).#505, folded in
The pin moves
2.1.236→2.1.258: Claude Fable 5.1 arrived in 2.1.257, and the pin is deliberately unwalkable at runtime (#196), so a stale one can only be fixed by a rebuild.npm install -gexiting 0 is not evidence thatclauderuns — the tarball shipsbin/claude.exeas a stub resolved bypostinstall— so the build now runs it against the pin. That is the packaging that broke 2.1.237 (#147/#148) and held the pin for months.Verified in a clean
node:22-bookwormcontainer: 2.1.258 installs non-stub,claude --versionprints2.1.258 (Claude Code)as root with no config, the guard passes, and it correctly rejects a wrong version.A trap that bit twice
#inside abuild-args: |block is content, not a comment, and reaches buildx as a build arg.build.ymlalready carried a note saying so because the mistake had been made once; it was made again while writing this change. It is nowtest_no_build_args_block_contains_a_commentover both workflows instead of a comment in one — confirmed to fail on an injected comment before being kept.Docs
DEPLOYMENT.md§1.1 compares the three shapes and states the AIO's dev-pod posture plainly (sudo, sshd, DooD, noread_only); §7 replaces the "CLI-free by design" claim with the generic-vs-estate tag table;CUSTOMISATION.mdgains theFROM vogt-stack@sha256:...worked example, which is how the private overlays are actually built. Four sites said "no engine image is published" — true of the engine alone, and now stated that way.Supersedes
Closes #505. #502 and PR #503 are closed as resolved-by-design: their stated harm (pin
latest, get an agent-less pod) disappears once the release carries the CLIs, and #502's "stop tagginglatest" proposal inverts oncevogt-stackis the supported public AIO.Not in scope
Plan steps 2 (thin
Dockerfile.pod) and 3 (GHCR visibility flip) are deliberately held: step 2 is gated on the private overlay parity-validating onvogt-dev, and step 3 should follow the first generic release so the first public digest is not the Cadastre-carrying v0.4.0.Verification
uv run pytest1315 passed / 25 skipped / 91% coverage ·mypyclean ·ruff check+format --checkclean ·check_docs.pyclean ·docker compose -f deploy/stack.compose.yml configrenders.🤖 Generated with Claude Code
https://claude.ai/code/session_01RzFCTnWGff1k4FyX1HQCYM