fix(entrypoint,smoke): link image-baked skills early to fix smoke race

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.
This commit is contained in:
Joakim Persson
2026-06-23 14:29:52 +02:00
parent 2abfee141b
commit 9be2f9fcda
2 changed files with 27 additions and 22 deletions
+26 -22
View File
@@ -40,6 +40,32 @@ if [ -d "$SKEL_DIR" ]; then
done done
fi 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 # ── MemPalace: initialize palace for the workspace if mempalace is installed
# Creates the palace directory structure on first run. Idempotent — skips # Creates the palace directory structure on first run. Idempotent — skips
# if palace already exists, so upgrades from older versions preserve # if palace already exists, so upgrades from older versions preserve
@@ -170,28 +196,6 @@ case "${STUDIO_EXPOSE:-}" in
;; ;;
esac 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 ── # ── Skillset: deploy skills/instructions from mounted skillset repo ──
# When the skillset repo is mounted (at $HOME/skillset or /workspace/skillset), # When the skillset repo is mounted (at $HOME/skillset or /workspace/skillset),
# run the deploy script to create relative symlinks for skills and instructions. # run the deploy script to create relative symlinks for skills and instructions.
+1
View File
@@ -162,6 +162,7 @@ for i in $(seq 1 45); do
if docker exec "$CID" sh -c ' if docker exec "$CID" sh -c '
test -L /home/developer/.pi/agent/keybindings.json && \ test -L /home/developer/.pi/agent/keybindings.json && \
test -L /home/developer/.pi/agent/extensions/mempalace.ts && \ 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=$(ls -1 /home/developer/.pi/agent/extensions/*.ts 2>/dev/null | wc -l) && \
[ "$count" -ge 4 ] [ "$count" -ge 4 ]
' >/dev/null 2>&1; then ' >/dev/null 2>&1; then