From d619a6e2ecb9b2163f48e11e86a3dc84698c66d5 Mon Sep 17 00:00:00 2001 From: Joakim Persson Date: Tue, 23 Jun 2026 14:29:52 +0200 Subject: [PATCH] fix(entrypoint,smoke): link image-baked skills early to fix smoke race MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The runtime 'pi-devbox-environment skill linked' smoke assertion failed in CI run 408 (gating build-variant). Root cause: the skill-linking block ran AFTER the pi-toolkit/extensions deploy, but the smoke readiness gate only waits on pi-deploy markers (keybindings.json, mempalace.ts) — which land before the skill symlink — so the assertion sampled too early. - entrypoint-user.sh: move the image-baked-skills symlink loop to run early (before the pi deploy block), so it completes before any readiness marker. Still before the skillset deploy, so foreign-link semantics are unchanged. - smoke-test.sh: add the skill symlink to the readiness gate as well. Build-time checks (baked skill, append snippet, merged AGENTS marker) all passed in 408; only the timing of the runtime check was wrong. --- entrypoint-user.sh | 48 +++++++++++++++++++++++-------------------- scripts/smoke-test.sh | 1 + 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/entrypoint-user.sh b/entrypoint-user.sh index 6a0fda0..08c5eb5 100755 --- a/entrypoint-user.sh +++ b/entrypoint-user.sh @@ -40,6 +40,32 @@ if [ -d "$SKEL_DIR" ]; then done fi +# ── Image-baked skills: link into ~/.agents/skills ─────────────────── +# Skills shipped IN the image (under /usr/local/share/pi-devbox/skills/) are +# made available regardless of whether a skillset repo is mounted. Done EARLY +# — before the pi-toolkit/extensions deploy below — so the symlinks exist by +# the time anything gates on "container ready": the smoke-test readiness probe +# waits on pi-deploy markers (keybindings.json, mempalace.ts) that only land +# AFTER this point, so linking here closes a sample-too-early race that failed +# the runtime skill-link assertion. Pointing at the image path (/usr/local/...) +# keeps the skill fresh from the image and surviving volume recreate (unlike +# anything baked under a home dir, which a named volume would shadow). Created +# only when absent, so a same-named skillset skill (deployed later, at the end +# of this script) or a user override is never clobbered; the skillset deploy +# classifies these as foreign-links and its --prune-stale pass leaves them +# alone (only dangling symlinks are pruned). +DEVBOX_SKILLS_SRC=/usr/local/share/pi-devbox/skills +if [ -d "$DEVBOX_SKILLS_SRC" ]; then + mkdir -p "$HOME/.agents/skills" + for _sk in "$DEVBOX_SKILLS_SRC"/*/; do + [ -d "$_sk" ] || continue + _skname=$(basename "$_sk") + if [ ! -e "$HOME/.agents/skills/$_skname" ]; then + ln -s "${_sk%/}" "$HOME/.agents/skills/$_skname" + fi + done +fi + # ── MemPalace: initialize palace for the workspace if mempalace is installed # Creates the palace directory structure on first run. Idempotent — skips # if palace already exists, so upgrades from older versions preserve @@ -170,28 +196,6 @@ case "${STUDIO_EXPOSE:-}" in ;; esac -# ── Image-baked skills: link into ~/.agents/skills ─────────────────── -# Skills shipped IN the image (under /usr/local/share/pi-devbox/skills/) are -# made available regardless of whether a skillset repo is mounted. We symlink -# each into ~/.agents/skills/ so pi discovers it. Pointing at the image path -# (/usr/local/...) means the skill is always fresh from the image and survives -# volume recreate (unlike anything baked under a home dir, which a named volume -# would shadow). Created only when absent, so a same-named skillset skill or a -# user override is never clobbered. The skillset deploy below classifies these -# as foreign-links (symlinks not pointing into the skillset repo) and leaves -# them alone — only dangling symlinks are pruned by --prune-stale. -DEVBOX_SKILLS_SRC=/usr/local/share/pi-devbox/skills -if [ -d "$DEVBOX_SKILLS_SRC" ]; then - mkdir -p "$HOME/.agents/skills" - for _sk in "$DEVBOX_SKILLS_SRC"/*/; do - [ -d "$_sk" ] || continue - _skname=$(basename "$_sk") - if [ ! -e "$HOME/.agents/skills/$_skname" ]; then - ln -s "${_sk%/}" "$HOME/.agents/skills/$_skname" - fi - done -fi - # ── Skillset: deploy skills/instructions from mounted skillset repo ── # When the skillset repo is mounted (at $HOME/skillset or /workspace/skillset), # run the deploy script to create relative symlinks for skills and instructions. diff --git a/scripts/smoke-test.sh b/scripts/smoke-test.sh index f9bc9b1..f710dba 100755 --- a/scripts/smoke-test.sh +++ b/scripts/smoke-test.sh @@ -162,6 +162,7 @@ for i in $(seq 1 45); do if docker exec "$CID" sh -c ' test -L /home/developer/.pi/agent/keybindings.json && \ test -L /home/developer/.pi/agent/extensions/mempalace.ts && \ + test -L /home/developer/.agents/skills/pi-devbox-environment && \ count=$(ls -1 /home/developer/.pi/agent/extensions/*.ts 2>/dev/null | wc -l) && \ [ "$count" -ge 4 ] ' >/dev/null 2>&1; then