You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A development environment inside container workrooms #308
🤖 Left by Claude Code, from the eng review of the local-container workrooms plan.
Problem
The workroom-host image (vcs/scripts/ssh-fixture/Dockerfile, FIXTURE=0) installs only openssh-server git procps ca-certificates. The workroom user has no sudo, and creating a container workroom runs no setup script (docs/designs/remote-workrooms.md:1583). So a fresh container has no language toolchain and no agent CLI (claude, codex), and no way to install either. Git and a terminal work, but an agent can't run a project's tests or even start.
The local-container issue ships with the copy "git and a terminal; tooling setup comes later". This issue is that later.
Options to compare
Passwordless sudo plus the project's existing workroom setup script. The script runs in the base and is baked in, so derived workrooms inherit it. This reuses internal/script, which local workrooms already run, and the container is the security boundary.
devcontainer.json support, a format many repositories already have.
A per-project image.
Acceptance
One real project, inside a container workroom, installs its dependencies, runs its tests and starts an agent CLI.
The owner wants a container workroom's image and container to be fully customisable. workroom-host can't offer that, because it is the far side the driver needs: sshd, the supervisor loop, host-key minting and the workroom user. So this proposes dropping the image and ssh from the container driver. It is written up as an amendment to docs/designs/remote-workrooms.md (the #309 "As built" section, "Not done"), committed locally as 5bd5f24 and not pushed yet.
Shape
Transport.exec, openStream and attachCommand become docker exec -i (relay, bootstrap) and docker exec -it (a pane, spawned directly by libghostty, so no bridge process). ssh was only the carrier: port forwards and the credential relay already ride the daemon connection. ADR 0028's bar holds, because anyone who can reach the Docker socket already has a root shell in the container.
Supervisor. The entrypoint is the bundled static workroomd serve, run with --init --restart unless-stopped. The image's own ENTRYPOINT/CMD don't run, as with devcontainers' default overrideCommand.
Daemon in.docker create, then docker cp (or a read-only bind mount), then docker start. Apple's container can't copy into a created container and has no restart policy, so it would take the bind mount plus the existing start-on-open.
Configuration.devcontainer.json, which DevContainerPorts already reads for ports: image/build, mounts, containerEnv, remoteUser, runArgs. Projects without one get a default image and a setting to choose another. features come later.
The image must have git and a shell for panes. Nothing else.
Measured on Docker Desktop (arm64) with the Dev build's workroomd-linux-aarch64, with no image changes. Images: debian:bookworm-slim, alpine:3.22, node:22 and python:3.13-slim.
The daemon served on all four.
20 MB of random bytes made the round trip through docker exec -i intact.
hand-off --force answered handed off.
The daemon served again after docker restart.
A pane attached through docker exec -it ran a command and showed its output.
The bind-mount variant worked on alpine.
As node:22's node user it worked once its socket folder existed and was owned by node.
Only node:22 has git. Not measured: Apple's runtime, throughput beyond 20 MB, and a stdin close mid-stream. DevPod, the devcontainers CLI and Coder reach arbitrary images the same way, and none of them needs sshd in the image.
Costs
A container-specific install path. The app puts the new build in place from the Mac and points hand-off --binary at it, instead of using install.sh's shell stage-then-rename.
Two daemon fixes. serve doesn't create its socket's folder, and the shell falls back to /bin/zsh when SHELL is unset.
Containers already made from workroom-host (Nightly and Dev only) keep the ssh path or are made again.
Removes:workroom-host, host-image.yml and the ghcr package, the WorkroomHostImage pin, sshd hardening, host-key minting and the published ssh port.
Rejected: layering a static ssh server onto the user's image (a second Linux artifact, and it still needs a shell), and FROM workroom-host (Debian only, and a Dockerfile per user).
Open (owner): does stable wait for this, or first ship container workrooms on workroom-host?
Activity
feat(macapp): forward the ports a container workroom's devcontainer.j…
joelmoss commentedon Oct 23, 2026
🤖 Left by Claude Code.
Proposal: any image, reached over
docker execThe owner wants a container workroom's image and container to be fully customisable.
workroom-hostcan't offer that, because it is the far side the driver needs: sshd, the supervisor loop, host-key minting and theworkroomuser. So this proposes dropping the image and ssh from the container driver. It is written up as an amendment todocs/designs/remote-workrooms.md(the #309 "As built" section, "Not done"), committed locally as 5bd5f24 and not pushed yet.Shape
exec,openStreamandattachCommandbecomedocker exec -i(relay, bootstrap) anddocker exec -it(a pane, spawned directly by libghostty, so no bridge process). ssh was only the carrier: port forwards and the credential relay already ride the daemon connection. ADR 0028's bar holds, because anyone who can reach the Docker socket already has a root shell in the container.workroomd serve, run with--init --restart unless-stopped. The image's own ENTRYPOINT/CMD don't run, as with devcontainers' defaultoverrideCommand.docker create, thendocker cp(or a read-only bind mount), thendocker start. Apple'scontainercan't copy into a created container and has no restart policy, so it would take the bind mount plus the existing start-on-open.devcontainer.json, whichDevContainerPortsalready reads for ports:image/build,mounts,containerEnv,remoteUser,runArgs. Projects without one get a default image and a setting to choose another.featurescome later.Measured on Docker Desktop (arm64) with the Dev build's
workroomd-linux-aarch64, with no image changes. Images:debian:bookworm-slim,alpine:3.22,node:22andpython:3.13-slim.docker exec -iintact.hand-off --forceansweredhanded off.docker restart.docker exec -itran a command and showed its output.node:22'snodeuser it worked once its socket folder existed and was owned bynode.Only
node:22has git. Not measured: Apple's runtime, throughput beyond 20 MB, and a stdin close mid-stream. DevPod, the devcontainers CLI and Coder reach arbitrary images the same way, and none of them needs sshd in the image.Costs
hand-off --binaryat it, instead of usinginstall.sh's shell stage-then-rename.docker exec's 125–127 exit codes instead of ssh's.servedoesn't create its socket's folder, and the shell falls back to/bin/zshwhenSHELLis unset.workroom-host(Nightly and Dev only) keep the ssh path or are made again.Removes:
workroom-host,host-image.ymland the ghcr package, theWorkroomHostImagepin, sshd hardening, host-key minting and the published ssh port.Rejected: layering a static ssh server onto the user's image (a second Linux artifact, and it still needs a shell), and
FROM workroom-host(Debian only, and a Dockerfile per user).Open (owner): does stable wait for this, or first ship container workrooms on
workroom-host?docs(remote): propose any-image container workrooms over docker exec (#…
docs(remote): any-image containers measured on Apple's runtime; stabl…
docs(remote): any-image containers: eng review decisions (#308)
docs(remote): devcontainer hooks run before the setup script; honour …
fix(daemon): make a missing socket folder and use the passwd shell wh…
docs(remote): T1 done; postStart's start id is the program-status boot (
docs(remote): the app still owes reading boot and holding panes for p…
feat(macapp): DevContainerConfig reads the whole devcontainer.json (#308
35 remaining items
chore: stop building and pinning the workroom-host image (#308, T9)
test: the container suites run on a stock image through exec (#308, T10)
feat(macapp): a container made before #308 says to recreate its workr…
docs: measure the Docker CLI each container pane keeps (#308, T13)
docs: container workrooms run any image, made from devcontainer.json (#…
fix(macapp): a root-only devcontainer.json builds from the root's Doc…
fix(macapp): a devcontainer build path the commit lacks fails at the …
docs, test: record the owner's #308 decisions and pin the start commit (
test: pin the devcontainer refusals, the already-this-user drop, repe…
fix(macapp): drop the per-Mac default image setting; renumber ADR 0060 (
fix(macapp): pre-landing review fixes (#308)
fix(macapp): second pre-landing review fixes (#308)
docs: ADRs 0029 and 0036 are superseded in part by 0060; boxd reaches…
chore: track the #308 /ship review follow-ups
fix(macapp): a container build reads its commit as a checkout does, a…