@@ -72,6 +72,22 @@ The readiness banner is what you care about. It gates on **three** signals simul
7272
7373Only once all three are true does the banner fire and the host's browser auto-open.
7474
75+ > ** Process running ≠ UI rendered.** The three gates above tell you the
76+ > backing processes are alive, not that Electron has actually painted.
77+ > A devcontainer-in-CI proof captured a blank screen because all three
78+ > gates passed while the window was still mid-first-paint. For
79+ > agent-grade readiness (e.g. before driving the app via ` xdotool ` or
80+ > taking a screenshot to feed to a vision model), add this gate:
81+ >
82+ > ``` bash
83+ > docker exec -u node " $CONTAINER " bash -c \
84+ > ' DISPLAY=:99 xdotool search --class ToolHive >/dev/null 2>&1'
85+ > ` ` `
86+ >
87+ > ` xdotool search --class` only succeeds once the main window is mapped
88+ > on Xvfb. A short settling sleep (~2s) after that first match is cheap
89+ > insurance against catching a partially rendered frame.
90+
7591---
7692
7793# # Per-worktree isolation
@@ -146,13 +162,33 @@ All commands run via `docker exec` against the container with `DISPLAY=:99` set
146162
147163### See the screen (screenshots)
148164
165+ Use the project's helper script — it auto-finds the container, captures the
166+ root window, and streams the PNG out to the host. Prints the absolute host
167+ path on stdout so it composes:
168+
149169``` bash
150- # Take a PNG of the whole virtual framebuffer
170+ SHOT=$( scripts/devcontainer-screenshot.sh)
171+ # or with an explicit path:
172+ scripts/devcontainer-screenshot.sh /tmp/shot.png
173+ ```
174+
175+ ** Why a helper script and not just ` docker cp ` ?** ` /tmp ` (and possibly
176+ other paths) inside the devcontainer is mounted as ` tmpfs ` . Docker's
177+ ` docker cp ` cannot read from tmpfs mounts — it only traverses the
178+ container's overlay layers — so the obvious one-liner
179+
180+ ``` bash
181+ # DON'T — silently broken: import succeeds, ls confirms the file,
182+ # but docker cp says "Could not find the file in container".
151183docker exec " $CONTAINER " bash -c ' DISPLAY=:99 import -window root /tmp/shot.png'
152- # Copy it to the host for viewing / feeding to a vision model
153184docker cp " $CONTAINER :/tmp/shot.png" /tmp/shot.png
154185```
155186
187+ ** fails everywhere** (CI and local). The helper bypasses ` docker cp ` by
188+ streaming the file via ` docker exec cat ` (see ` scripts/devcontainer-steal.sh `
189+ for the generic version — use that one to extract any tmpfs file, e.g. logs
190+ or generated artifacts, not just screenshots).
191+
156192` import ` is from ImageMagick. For a specific window only, use ` xwininfo ` to get the WID then ` import -window <WID> ` .
157193
158194### See the window tree (what's there, where, which is focused)
0 commit comments