@@ -116,6 +116,7 @@ The first start creates local and generated files when missing:
116116- ` .codegeist/.local.env `
117117- ` .chrome/ `
118118- ` .devcontainer/.env `
119+ - ` .devcontainer/.Xauthority.gen `
119120- ` .devcontainer/Dockerfile.merged.gen `
120121- ` .devcontainer/compose.local.gen.yml `
121122- ` .devcontainer/compose.user.gen.yml ` , an ignored bridge to optional
@@ -144,9 +145,10 @@ file does not exist. It does not delete the legacy files and does not migrate a
144145root ` Dockerfile ` ; move devcontainer image extensions to ` .codegeist/Dockerfile `
145146manually if needed.
146147
147- Do not edit ` .devcontainer/.env ` , ` .devcontainer/Dockerfile.merged.gen ` , or
148- ` .devcontainer/compose.local.gen.yml ` or ` .devcontainer/compose.user.gen.yml ` ;
149- they are regenerated by ` initialize.sh ` . Put manual runtime overrides in
148+ Do not edit ` .devcontainer/.env ` , ` .devcontainer/.Xauthority.gen ` ,
149+ ` .devcontainer/Dockerfile.merged.gen ` , ` .devcontainer/compose.local.gen.yml ` , or
150+ ` .devcontainer/compose.user.gen.yml ` ; they are regenerated by ` initialize.sh ` .
151+ Put manual runtime overrides in
150152` .codegeist/.local.env ` , local Compose overrides in ` .codegeist/compose.local.yml ` ,
151153and devcontainer image extensions in ` .codegeist/Dockerfile ` instead. Create the
152154Compose and Dockerfile override files only when the repository needs them.
@@ -223,26 +225,34 @@ chrome https://example.test
223225```
224226
225227The visible command does not start VNC or noVNC, and it does not treat a non-empty
226- display variable as proof that a display server is reachable. A Wayland candidate
227- is usable only when ` WAYLAND_DISPLAY ` and ` XDG_RUNTIME_DIR ` identify an existing
228- Unix socket. When that socket exists, the launcher prefers it, removes an
229- inherited invalid ` DISPLAY ` , and starts Chrome with ` --ozone-platform=wayland ` .
230- A local X11 value such as ` DISPLAY=:0 ` is usable only when the matching
231- ` /tmp/.X11-unix/X0 ` socket exists inside the container. The shared Compose config
232- does not mount ` /tmp/.X11-unix ` by default. SSH-forwarded values such as
233- ` DISPLAY=localhost:10.0 ` remain supported through host networking and Xauthority
234- normalization; explicitly configured remote X11 host values are passed through as
235- caller-managed connections.
236-
237- ` initialize.sh ` still writes the host-side ` DISPLAY ` visible to
238- ` initializeCommand ` into ` .devcontainer/.env ` as ` DEVCONTAINER_DISPLAY ` , and
239- Compose passes that candidate into the container on create. The launcher rereads
240- the mounted file before starting visible Chrome, so a VS Code reopen can refresh
241- SSH X11 state when the existing container is reused. If no usable Wayland or X11
242- backend exists, the launcher exits before Google Chrome starts and reports the
243- missing socket paths. Use ` chrome --headless ... ` , SSH X11 forwarding, or an
244- explicit project-local socket mount instead of broad host access such as
245- ` xhost + ` .
228+ display variable as proof that a display server is reachable. During
229+ ` initializeCommand ` , ` initialize.sh ` detects an existing host Wayland socket from
230+ ` WAYLAND_DISPLAY ` and ` XDG_RUNTIME_DIR ` (or ` /run/user/<uid>/wayland-0 ` ) and adds a
231+ generated bind for only that socket. When the mounted socket is reachable, the
232+ launcher prefers it, removes inherited ` DISPLAY ` , and starts Chrome with
233+ ` --ozone-platform=wayland ` . A local X11 value such as ` DISPLAY=:0 ` remains usable
234+ only when ` /tmp/.X11-unix/X0 ` exists inside the container; the shared Compose
235+ config does not mount local X11 sockets by default.
236+
237+ VS Code SSH reconnects can allocate a new loopback display number while reusing
238+ an existing container. Each initialize run atomically refreshes the selected
239+ workspace's ` .devcontainer/.env ` and ignored ` .devcontainer/.Xauthority.gen ` .
240+ The launcher rereads those files on every visible start, probes
241+ ` DISPLAY=localhost:N.0 ` or ` 127.0.0.1:N.0 ` with a short ` xdpyinfo ` check, and, if
242+ needed, normalizes the matching ` /unix:N ` cookie through unique temporary
243+ Xauthority aliases. It
244+ exits before Google Chrome starts when no candidate is reachable. Worktrees keep
245+ separate generated state and ` .chrome ` profiles, so multiple VS Code instances
246+ on one host do not overwrite each other's runtime display files. Explicit
247+ non-loopback X11 hosts remain caller-managed.
248+
249+ Wayland discovery can mount only a socket that exists when the container is
250+ created. ` initialize.sh ` cannot create a graphical host session, and a socket
251+ that appears later cannot be added to an already running container without
252+ recreation. SSH X11 reconnect recovery does not have that limitation because it
253+ uses host networking and workspace-local refreshed authority state. Use
254+ ` chrome --headless ... ` when no visible backend is available; broad host access
255+ such as ` xhost + ` is neither required nor recommended.
246256
247257Plain visible ` chrome ` uses ` $DEVCONTAINER_WORKSPACE_FOLDER/.chrome ` unless the
248258caller passes an explicit ` --user-data-dir ` . Visible Chrome also disables
@@ -543,10 +553,10 @@ The same generated root files must still be ignored by the consuming repository:
543553/.chrome/
544554```
545555
546- The ` .devcontainer/.env ` , ` .devcontainer/Dockerfile.merged .gen ` ,
547- ` .devcontainer/compose.local .gen.yml ` , and ` .devcontainer/compose.user .gen.yml `
548- files are generated by the kit inside the submodule checkout and intentionally
549- ignored there.
556+ The ` .devcontainer/.env ` , ` .devcontainer/.Xauthority .gen ` ,
557+ ` .devcontainer/Dockerfile.merged .gen ` , ` .devcontainer/compose.local .gen.yml ` , and
558+ ` .devcontainer/compose.user.gen.yml ` files are generated by the kit inside the
559+ submodule checkout and intentionally ignored there.
550560
551561The kit also creates root ` .oc_local/ ` for ` OPENCODE_CONFIG_DIR ` so OpenCode can
552562bootstrap in fresh devcontainers. When the consuming repository does not track a
@@ -620,9 +630,10 @@ It may:
620630 ` compose.local.yml ` there when it already exists and the new file is missing;
621631 this file is not ignored automatically
622632- create root ` .oc_local/ ` for workspace-local OpenCode config
623- - write ` .devcontainer/.env ` , ` .devcontainer/Dockerfile.merged.gen ` , and
624- ` .devcontainer/compose.local.gen.yml ` generated runtime values such as the
625- container hostname, hostname loopback resolution, and numeric runtime user
633+ - write ` .devcontainer/.env ` , ` .devcontainer/.Xauthority.gen ` ,
634+ ` .devcontainer/Dockerfile.merged.gen ` , and ` .devcontainer/compose.local.gen.yml `
635+ generated runtime values such as display state, container hostname, hostname
636+ loopback resolution, and numeric runtime user
626637- update generated local env values when their content changed
627638- compute host UID
628639- compute a stable project name
@@ -641,22 +652,22 @@ Preferred pattern:
6416521 . ` initialize.sh ` writes ` .codegeist/.local.env ` .
6426532 . ` initialize.sh ` migrates a legacy root ` compose.local.yml ` into
643654 ` .codegeist/compose.local.yml ` only when that legacy file exists.
644- 3 . ` initialize.sh ` writes ` .devcontainer/.env ` , including the host-side
645- ` DISPLAY ` value as ` DEVCONTAINER_DISPLAY ` when one is present .
646- 4 . ` initialize.sh ` writes ` .devcontainer/Dockerfile.merged.gen ` .
647- 5 . ` initialize.sh ` writes ` .devcontainer/compose.local.gen.yml ` .
648- 6 . ` initialize.sh ` writes ` .devcontainer/compose.user.gen.yml ` , either empty or
655+ 3 . ` initialize.sh ` writes ` .devcontainer/.env ` , including host display state.
656+ 4 . ` initialize.sh ` atomically refreshes ` .devcontainer/.Xauthority.gen ` .
657+ 5 . ` initialize.sh ` writes ` .devcontainer/Dockerfile.merged.gen ` .
658+ 6 . ` initialize.sh ` writes ` .devcontainer/compose.local.gen.yml ` .
659+ 7 . ` initialize.sh ` writes ` .devcontainer/compose.user.gen.yml ` , either empty or
649660 copied from ` .codegeist/compose.local.yml ` .
650- 7 . ` .devcontainer/docker-compose.yml ` reads ` .env ` and
661+ 8 . ` .devcontainer/docker-compose.yml ` reads ` .env ` and
651662 ` ../.codegeist/.local.env ` with ` env_file ` .
652- 8 . ` devcontainer.json ` includes ` compose.local.gen.yml ` and
663+ 9 . ` devcontainer.json ` includes ` compose.local.gen.yml ` and
653664 ` compose.user.gen.yml ` .
654- 9 . ` .devcontainer/docker-compose.yml ` owns the workspace and parent Git mounts.
655- 10 . ` devcontainer.json ` uses ` ${localEnv:USER} ` for ` remoteUser ` and
656- ` containerUser ` .
657- 11 . ` docker-compose.yml ` passes ` DEVCONTAINER_DISPLAY ` into the container as
658- ` DISPLAY ` so SSH X11 forwarding follows the initialize-time environment .
659- 12 . Container-side tools read normal environment variables from Compose.
665+ 10 . ` .devcontainer/docker-compose.yml ` owns the workspace and parent Git mounts.
666+ 11 . ` devcontainer.json ` uses ` ${localEnv:USER} ` for ` remoteUser ` and
667+ ` containerUser ` .
668+ 12 . ` docker-compose.yml ` passes initial display values into the container; the
669+ Chrome launcher rereads the workspace files after SSH reconnects .
670+ 13 . Container-side tools read normal environment variables from Compose.
660671
661672Example Compose shape:
662673
@@ -744,7 +755,8 @@ The tests should verify at least:
744755- ` .codegeist/.local.env` is created or preserved by `initializeCommand`
745756- root `.oc_local/` is created for OpenCode and ignored unless the repository
746757 tracks a project overlay there
747- - ` .devcontainer/.env` , `.devcontainer/Dockerfile.merged.gen`,
758+ - ` .devcontainer/.env` , `.devcontainer/.Xauthority.gen`,
759+ ` .devcontainer/Dockerfile.merged.gen` ,
748760 ` .devcontainer/compose.local.gen.yml` , and
749761 ` .devcontainer/compose.user.gen.yml` are regenerated by `initializeCommand`
750762- the generated container hostname matches host, repo, and branch context
@@ -893,7 +905,8 @@ migrates a legacy root `.local.env` into `.codegeist/.local.env` when needed,
893905and links the worktree `.codegeist/.local.env` back to the main root file. When
894906the devcontainer starts from an already selected checkout, `initializeCommand`
895907writes that checkout's
896- ` .devcontainer/.env` , `.devcontainer/Dockerfile.merged.gen`,
908+ ` .devcontainer/.env` , `.devcontainer/.Xauthority.gen`,
909+ ` .devcontainer/Dockerfile.merged.gen` ,
897910` .devcontainer/compose.local.gen.yml` , and `.devcontainer/compose.user.gen.yml`
898911without nesting another worktree for the same branch.
899912
@@ -959,6 +972,7 @@ Typical examples:
959972
960973- ` .codegeist/.local.env`
961974- ` .devcontainer/.env`
975+ - ` .devcontainer/.Xauthority.gen`
962976- ` .devcontainer/Dockerfile.merged.gen`
963977- ` .devcontainer/compose.local.gen.yml`
964978- ` .devcontainer/compose.user.gen.yml`
0 commit comments