feat(entrypoint): link ~/.pi/agent/models.json to a mounted shared file
pi reads custom providers from ~/.pi/agent/models.json, and ~/.pi is the devbox-pi-config named volume. A file baked into the image would only seed a fresh volume, once. A hand-made link is one more step on every new volume: on 2026-10-12 that was the same `ln -s /opt/fleet-pi/models.json …` once per device, for one fleet-shared file. New rootfs/usr/local/lib/pi-devbox/link-pi-models.sh, called from entrypoint-user.sh after the pi-toolkit and pi-extensions installs. When /opt/fleet-pi/models.json exists (PI_MODELS_JSON overrides the path, =off disables it), it links ~/.pi/agent/models.json to it, honouring PI_CODING_AGENT_DIR. It only ever creates a link where nothing exists: a real file or a link of the user's own is left alone, with one NOTE line. With nothing mounted, it does nothing and prints nothing. A link whose target later vanishes is harmless; measured with pi 1.0.0, a dangling models.json behaves like a missing one (rc 0, no error, no custom models). Tests: - scripts/test-link-pi-models.sh: 13 two-sided cases against a throwaway HOME. Wired into lint.yml, so it runs on every push and not only at release. - Of 11 mutations, 10 are caught. The 11th (ln -s -> ln -sfn on the final link) is unreachable behind the guards. - smoke-test.sh: with nothing mounted no link appears, and the script links a mounted file. Both commands were run under dash here. - recreate-sanity-check.sh: pass, warn or fail on the link, but only when a shared file is mounted. Here it passes. Docs: - README "Custom model providers (models.json)": mount the DIRECTORY (git pull renames, and a single-file mount then shows "No such file" until recreate), keep keys in .env as "$NAME". - .env.example: PI_MODELS_JSON. Local gates green: lint-shell, check-workflow-shell, check-dockerfile-directives, check-base-hash, check-doc-drift.
This commit is contained in:
@@ -879,6 +879,40 @@ If you use Bedrock as pi's LLM provider:
|
||||
The pi-toolkit AWS env loader (in `~/.pi/agent/`) prepares Bedrock
|
||||
inference-profile model IDs (with `eu.` / `us.` prefixes) automatically.
|
||||
|
||||
## Custom model providers (`models.json`)
|
||||
|
||||
pi reads extra providers from `~/.pi/agent/models.json`. That can be any
|
||||
OpenAI-, Anthropic- or Google-compatible endpoint: a company gateway, vLLM,
|
||||
Ollama, LM Studio and so on (pi's
|
||||
[models.md](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/models.md)).
|
||||
`~/.pi` is the `devbox-pi-config` volume. A file you put there by hand survives
|
||||
recreates, but every new volume starts without one: another device, or after
|
||||
`down -v`.
|
||||
|
||||
To share one file across devices, keep it in a host directory and mount that
|
||||
**directory** read-only at `/opt/fleet-pi`. At every start the entrypoint links
|
||||
`~/.pi/agent/models.json` to `/opt/fleet-pi/models.json`:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./pi-shared:/opt/fleet-pi:ro # a directory containing models.json
|
||||
```
|
||||
|
||||
- **Mount the directory, not the file.** `git pull` and most editors replace a
|
||||
file by rename. A single-file bind mount then keeps showing the old one, or
|
||||
"No such file", until the next recreate. A directory mount shows the new file
|
||||
at once. pi reads `models.json` when it starts, so a pulled change reaches the
|
||||
next pi session without a recreate.
|
||||
- **Keep keys out of the file.** Write `"apiKey": "$MY_GATEWAY_KEY"` in
|
||||
`models.json` and put the value in `.env`, which `env_file:` already passes
|
||||
in. The file then holds no secret and can live in git.
|
||||
- **Nothing of yours is replaced.** A real `~/.pi/agent/models.json`, or a link
|
||||
of your own, is left alone; `docker logs` shows one `NOTE` line saying so. With
|
||||
nothing mounted, nothing happens.
|
||||
- `PI_MODELS_JSON` points at another path, and `PI_MODELS_JSON=off` disables the
|
||||
link. Check with `pi --list-models <provider>`. `recreate-sanity-check.sh`
|
||||
verifies the link whenever a shared file is mounted.
|
||||
|
||||
## Build pipeline
|
||||
|
||||
pi-devbox is built from this repo's CI in two phases:
|
||||
|
||||
Reference in New Issue
Block a user