Updating from inside the stack
./setup.sh detects when it runs inside one of the dev containers (DooD
socket mounted) and rebuilds through a throwaway builder mounted at the HOST
paths, where compose's ${HOME} interpolation and relative mounts resolve
correctly — and recreating your own container can't kill the script mid-run:
Same flags as on the host; host provisioning (disk, docker, nvidia) is
skipped inside since it only matters at first provision. Re-running stays
idempotent: only the image is rebuilt and containers recreated — named
volumes and the bind-mounted workspaces are never deleted. Host paths are
auto-detected from your own container's mount table (HOST_HOME / HOST_REPO
env vars override this when detection fails).
Manual equivalent
What setup.sh automates — two traps: compose interpolates ${HOME} and
resolves relative mounts using the client's paths (inside a container that
is /home/dev and /home/dev/workspaces/...), which the host daemon cannot
find; and recreating the container the command is running in kills the command
itself.
1. From a running service, update the others. Override the client paths so bind mounts resolve to real host paths:
HOME=<host home> docker compose \
--project-directory <host path to this repo> \
--env-file /home/dev/workspaces/ainvironment/.env \
-f /home/dev/workspaces/ainvironment/docker-compose.yml up -d
2. Full update, including the container you are in. Launch a throwaway builder over the socket, mounted at its own host path so client and daemon agree on every path — nothing in it belongs to the stack, so it can recreate everything:
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v <host path to this repo>:<host path to this repo> \
-w <host path to this repo> -e HOME=<host home> \
ainvironment/dev:latest docker compose up -d
macOS: HOME=/Users/<you>, repo /Users/<you>/workspaces/ainvironment.
Linux: HOME=/home/<you>, repo /home/<you>/workspaces/ainvironment.
Rebuilds pick up both changes automatically: a newer OPENCODE_VERSION (or
unset for the channel's latest) because nothing masks /home/dev/.opencode,
and any extensions added to the Dockerfile's list via the post_start hook.
Add --profile <name> to those calls for anything beyond the defaults — and
keep build separate from up. They share one image+tag, so three
parallel builders race on latest and fail with AlreadyExists; that split is
why setup.sh no longer uses up --build.
Next: Kubernetes — the Helm deployment plan.