Build and review in per-run container workspaces - #845
Merged
Conversation
The container kept a long-lived clone of the org repository in a named volume. Nothing ever advanced its working tree, so the pipeline's own skills and agents were frozen at whatever commit the volume was created with. The rename in #842 made that visible: the host began invoking crypter-devcontainer-implement while the container still only knew crypter-implement, and both orchestrators broke. Workspaces are now created per run at /work/{run-id} and deleted when the run ends, cloned from a read-only mount of the host's .git. A copy of the code no longer outlives the run that made it, so it cannot drift. The mount being read-only is what makes sharing history safe: the container reads commits and cannot move a ref or add an object. The host working tree is not mounted, so uncommitted work stays invisible to the agents. The orchestrator owns the lifecycle and the container skills assume a workspace exists, mirroring how /runs already works. This also retires the worktree add/remove pairing in every container skill, along with the stale worktree a crashed run used to leave behind. The image is built locally instead of pulled from GHCR. It carries tooling and no source, so a change to workspace.sh or the Dockerfile is a rebuild rather than a publish waiting on an approval. NuGet and pnpm caches move to named volumes. Workspaces are ephemeral, so without them every run would restore from nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The image is built locally and carries tooling rather than source, so nothing consumes the published copy. Publishing it on every merge to stable left a registry image nobody pulled and an approval gate on changes that only ever affect the machine making them. pr-build-devcontainer stays. It pushes nothing and catches a Dockerfile that does not build, which is the only part of the publish path that was earning its keep. The devcontainer environment on the repository has no jobs left referencing it and can be deleted from the repository settings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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 container kept a long-lived clone of the org repository in a named volume, and nothing ever advanced its working tree. The pipeline's own skills and agents live in that tree, so they were frozen at whatever commit the volume was created with. The rename in #842 made it fatal: the host now invokes
crypter-devcontainer-implementwhile the container still only knowscrypter-implement, so/crypter-changeand/crypter-triage-reviewboth fail at their firstdocker exec.Workspaces are now created per run at
/work/{run-id}and removed when the run ends, cloned from/host-git— a read-only mount of the host's.git. Nothing holding a copy of the code outlives the run that made it, so there is nothing left to drift. Read-only is what makes sharing history safe: the container reads commits and cannot move a ref or add an object. The host working tree is not mounted, so uncommitted work stays invisible to the agents.The orchestrators own the workspace lifecycle and the container skills assume one exists, mirroring how
/runsalready works. That retires theworktree add/worktree removepairing in every container skill and the stale worktree a crashed run used to leave behind.The devcontainer image is now local only. It is built from
.devcontainer/Dockerfile, taggedcrypter-devcontainer:local, and carries tooling rather than source, so nothing outside the machine that builds it ever consumes it.build-and-push-devcontainer.ymlis deleted along with the GHCR publish it performed.Things worth knowing as a reviewer:
pr-build-devcontainerstays. It pushes nothing and catches a Dockerfile that does not build.git config --system --add safe.directory /host-git. Git refuses to read a repository owned by another uid, and the mount is owned by the host user by design..devcontainer/clone-upstream.shis replaced by.devcontainer/workspace.sh.refs/pull/{n}/headinto its own repository and the workspace clone brings it across, since the container no longer has a network remote.Verified by building the image and running a workspace end to end: clone,
upstream/stableresolution, branch and commit,wasm-toolsrestore ofCrypter.Test.Web, refusal of writes to/host-git, and teardown.