entrypoint: link fleet pi extensions from the mounted config dir
Lint / skill-floor (push) Successful in 7s
Lint / hadolint (push) Successful in 15s
Lint / actionlint (push) Successful in 19s
Lint / doc-drift (push) Successful in 17s

pi auto-loads every .ts in ~/.pi/agent/extensions/, which lives in the
devbox-pi-config volume. A baked extension only seeds a fresh volume once, and a
hand-copied one is a per-device step that drifts — the same two problems
link-pi-models.sh was added for on 2026-10-12, one level down. This is also the
only path that reaches every host: four of them mount common/pi from
docker-compose-repo, and three cannot be reached from a devbox to create a
symlink by hand (measured: no ssh config entry, no name resolution, and this
instance's ~/.ssh-local/config carries no jump alias — only gitea and the
mempalace feed host are reachable).

link-pi-extensions.sh links each TOP-LEVEL *.ts from the mounted fleet directory
(default /opt/fleet-pi, the same directory that already carries models.json;
PI_EXTENSIONS_SRC overrides, =off disables). A symlink, not a single-file bind
mount, for the measured reason already documented for models.json: git pull
replaces a file by rename, and a file mount then serves stale content. Never
destructive — a real file of that name in ~/.pi/agent/extensions/ wins over the
fleet copy. Nested *.ts are deliberately not linked: the directory is fleet pi
config, not an extension tree.

- scripts/test-link-pi-extensions.sh: 16 two-sided cases (the negative half is
  the contract), all passing, wired into lint.yml beside the models one.
- smoke-test.sh and recreate-sanity-check.sh gained the matching in-image and
  on-device checks, each gated on the fleet directory actually holding *.ts so a
  device without a shared directory is not judged by them.
- README: the shared directory can carry extensions, and the rules that apply.

Also repairs a pre-existing release blocker, found while checking this change.
check-doc-drift.sh failed on pristine HEAD (verified in a clean worktree):
pi-extensions main moved 0d8e417 -> 4c1d28d without the SHA being named above
the v1.11.2 heading, and docker-publish.yml's resolve-versions has
needs: [lint-gate] — so the next tag could not have published. The CHANGELOG now
names 4c1d28d and describes the two confirm-destructive commits from their diff
(they stop the gate prompting on harmless redirects, and add tee/dd of= as write
forms); node --test test/confirm-destructive.test.mjs at 4c1d28d: 2 pass, 0 fail.

Local verification: lint-shell.sh (21 files, severity error), check-workflow-shell.sh,
check-skill-floor.sh, check-dockerfile-directives.sh, check-doc-drift.sh, and both
link-pi-*.sh contract suites all pass. actionlint and hadolint are not installed in
a devbox, so those CI steps are unvalidated here; the smoke-test addition runs only
inside the image at release time.
This commit is contained in:
Joakim Persson
2026-10-16 19:01:04 +02:00
parent 5becbba6c8
commit a6abe17edc
8 changed files with 307 additions and 1 deletions
+21
View File
@@ -986,6 +986,27 @@ To share one file across devices, keep it in a host directory and mount that
link. Check with `pi --list-models <provider>`. `recreate-sanity-check.sh`
verifies the link whenever a shared file is mounted.
### The same directory can carry pi extensions
pi auto-loads every `.ts` in `~/.pi/agent/extensions/`, which lives in the same
volume and so has the same problem. The entrypoint therefore links top-level
`*.ts` files from the mounted directory in as well, one line each:
pi extension: linked erdc-classifiers.ts -> /opt/fleet-pi/erdc-classifiers.ts
- Only **top-level** `*.ts` files are linked: `models.json`, a README or a
nested checkout in that directory is not an extension, and one is never loaded
by accident.
- Same never-destructive rule, with the same `NOTE` lines, and the same
reasoning that makes a link right where a single-file mount is not (a pulled
change is picked up at once).
- **Your own copy wins.** A real file of the same name in
`~/.pi/agent/extensions/` is left alone, so a local edit of a shared extension
is never overwritten.
- `PI_EXTENSIONS_SRC` points at another directory, and `PI_EXTENSIONS_SRC=off`
disables it. `recreate-sanity-check.sh` verifies each link whenever the shared
directory holds `*.ts`.
## Build pipeline
pi-devbox is built from this repo's CI in two phases: