Compare commits

...

2 Commits

Author SHA1 Message Date
pi 49d3e113ee docs: complete CHANGELOG/AGENTS + promote Unreleased -> v1.15.13e
Validate / docs-check (push) Successful in 7s
Validate / base-change-warning (push) Successful in 11s
Validate / validate-base (push) Successful in 3m33s
Validate / validate-with-pi (push) Successful in 4m35s
Validate / validate-omos (push) Successful in 6m59s
Validate / validate-pi-only (push) Successful in 3m30s
Validate / validate-omos-with-pi (push) Successful in 17m14s
Publish Docker Image / base-decide (push) Successful in 15s
Publish Docker Image / resolve-versions (push) Successful in 9s
Publish Docker Image / build-base (push) Successful in 31m45s
Publish Docker Image / smoke-base (push) Successful in 3m44s
Publish Docker Image / smoke-omos (push) Successful in 4m44s
Publish Docker Image / smoke-pi-only (push) Successful in 3m38s
Publish Docker Image / smoke-omos-with-pi (push) Successful in 8m54s
Publish Docker Image / smoke-with-pi (push) Successful in 10m44s
Publish Docker Image / build-variant-base (push) Successful in 14m24s
Publish Docker Image / build-variant-omos (push) Successful in 19m43s
Publish Docker Image / build-variant-pi-only (push) Successful in 18m42s
Publish Docker Image / build-variant-with-pi (push) Successful in 17m45s
Publish Docker Image / build-variant-omos-with-pi (push) Successful in 32m54s
Publish Docker Image / promote-base-latest (push) Successful in 9s
Publish Docker Image / update-description (push) Successful in 12s
- CHANGELOG: add the missing entry for the ~/.config/devbox-shell compose-doc
  commit (440218f); promote Unreleased -> v1.15.13e (2026-06-04) with a release
  summary (letter-suffix rebuild on opencode 1.15.13, picks up pi 0.78.1 + LAN
  key persistence + devbox-ssh-local chown fix + validate.yml false-neg fix).
- AGENTS.md: document the STRICT_REGISTRATION smoke-gate knob under CI quirks
  (kept in lockstep with the validate.yml/docker-publish-split.yml change).

Docs only; no image/behavior change. Tagging v1.15.13e after this lands.
2026-06-04 22:41:30 +02:00
pi f1e879ca6c docs: per-host ControlPath under ~/.ssh breaks pi --ssh (read-only mount)
The bind-mounted ~/.ssh/config is read before the baked Host * default and
SSH uses the first ControlPath it sees. A per-host block pointing ControlPath
under ~/.ssh/ (CGNAT-multiplexing pattern) wins but fails in-container because
~/.ssh is read-only, silently breaking pi --ssh <host> (falls back to local
tools). Documented the host-side fix: drop the override or repoint at the
writable /tmp/sshcm/. README + CHANGELOG only, no image change.
2026-06-04 22:31:54 +02:00
3 changed files with 50 additions and 1 deletions
+1
View File
@@ -104,6 +104,7 @@ cd /tmp && npm pack @earendil-works/pi-coding-agent@0.75.5 && tar -xzf earendil-
- **`actions/upload-artifact` and `actions/download-artifact` must stay at @v3 on Gitea.** v4+ uses a GitHub-Enterprise-specific Artifact API; runs fail with `GHESNotSupportedError`. If you need artifacts for a new reason (build logs, SBOMs, etc.), pin @v3 explicitly.
- **Step scripts run under `/bin/sh` (dash), not bash.** Avoid bash-isms like `${VAR//a/b}` parameter-pattern substitution; use POSIX alternatives (`tr`, `sed`) or declare `shell: bash` on the step.
- **`BUILDKIT_PROGRESS=plain`** is set at workflow level on `docker-publish-split.yml` so arm64-under-QEMU builds log each layer line-by-line. The default collapsed progress UI hides which step is stalled, which made diagnosing earlier hangs expensive.
- **`STRICT_REGISTRATION` gates the fork/recall *registration* smoke assertions.** `smoke-test.sh`'s two pi-extension registration checks (that `pi-fork`/`pi-observational-memory` registered in `~/.pi/agent/settings.json`) depend on the *base* entrypoint running `pi install /opt/<pkg>`. `validate.yml` builds variants from the **published** `base-latest`, which lags the in-repo entrypoint until a release rebuilds the base — so those checks would false-negative there. They are therefore warn-only unless `STRICT_REGISTRATION=1`: `validate.yml` leaves it unset (warn), and `docker-publish-split.yml` (which builds the base fresh in the same run) sets `STRICT_REGISTRATION: "1"` on the three pi-bearing smoke jobs to enforce them. Build-time `/opt` + `node_modules` checks stay hard in both paths. If you touch the registration checks or the base-freshness model, keep this flag wiring in lockstep across both workflows.
## Testing changes
+33 -1
View File
@@ -8,6 +8,30 @@ Tags follow `v{opencode_version}[letter]` — bare tag for the first build on a
## Unreleased
_(no changes since v1.15.13e)_
## v1.15.13e — 2026-06-04
Letter-suffix rebuild on opencode `1.15.13` (version unchanged). Picks up
**pi `0.78.1`** (resolved fresh by CI's `resolve-versions` job) plus the LAN-jump
key-persistence work, an entrypoint ownership fix for the new `devbox-ssh-local`
volume, a CI smoke false-negative fix, and documentation. Touches `entrypoint.sh`
and `setup-lan-access.sh` (both in the base hash), so `base-latest` /
`base-pi-only` advance and the fixes propagate to `pi-devbox`.
### Docs: per-host `ControlPath` overrides break `pi --ssh` (read-only `~/.ssh`)
Documented a gotcha in the README "Reaching your LAN" section: the bind-mounted
`~/.ssh/config` is read before the baked `Host *` default, and SSH uses the
first `ControlPath` it sees. A per-host block that sets `ControlPath` under
`~/.ssh/` (a common CGNAT-multiplexing pattern, e.g. `~/.ssh/cm/%r@%h:%p`) wins
but then fails inside the container because `~/.ssh` is mounted read-only — the
master socket can't bind. This silently breaks `pi --ssh <host>`: the SSH layer
fails and pi falls back to running its tools locally in the container. Fix is
host-side — drop the per-host `ControlPath` or repoint it at the writable
`/tmp/sshcm/%r@%h:%p` (works on both host and container, preserves multiplexing).
No image change; documentation only.
### Fixed: validate.yml false-negative on fork/recall registration checks
The push-to-main `validate.yml` builds variants FROM the published `base-latest`
@@ -48,7 +72,15 @@ stayed root-owned while `setup-lan-access.sh` runs as `developer` — both its
the persistence change. `entrypoint.sh` now chowns `~/.ssh-local` to the
developer user alongside the other named-volume mount points.
_(no other changes since v1.15.13d)_
### Docs: document the optional `~/.config/devbox-shell` mount in the compose template
`docker-compose.yml` now carries a commented-out `~/.config/devbox-shell` bind
mount with an explanatory note. It's the recommended home for host-owned shell
config: the image's `~/.bash_aliases` sources `~/.config/devbox-shell/bash_aliases`
if present, and `setup-lan-access.sh` reads `~/.config/devbox-shell/ssh-lan.conf`
for named-peer `ProxyJump host` overrides. A directory mount is preferred over
the single-file `~/.bash_aliases` mount because it survives editors' atomic-save.
Template comment only; no behavior change.
## v1.15.13d — 2026-06-04
+16
View File
@@ -187,6 +187,22 @@ Now `dssh my-nas` routes container → host → LAN peer, pulling HostName/User/
> This ships the **mechanism** only — your specific target hosts are facts about *your* network (and a laptop roams between several), so they live in your own host-side config, never baked into the image. Set `DEVBOX_LAN_ACCESS=off` to disable, or `=jump` to force it (e.g. native Linux with `extra_hosts: ["host.docker.internal:host-gateway"]`).
#### Gotcha: per-host `ControlPath` and `pi --ssh`
The base image bakes a `Host *` default (`/etc/ssh/ssh_config.d/00-devbox-controlmaster.conf`) that points `ControlPath` at the writable, per-container `/tmp/sshcm/` (created mode-700 on every start by `entrypoint-user.sh`). Multiplexing therefore works out of the box. **But your bind-mounted `~/.ssh/config` is read first, and SSH uses the first value it sees** — so any per-host block that sets its own `ControlPath` under `~/.ssh/` (a common CGNAT-multiplexing pattern, e.g. `ControlPath ~/.ssh/cm/%r@%h:%p`) **wins, and then fails inside the container** because `~/.ssh` is mounted **read-only** — the master socket can't bind (`cannot bind … Read-only file system`).
This bites `pi --ssh <host>` especially: the SSH layer fails to establish the master and pi silently falls back to running its `read`/`write`/`edit`/`bash` tools **locally in the container** instead of on the remote (watch for the missing `SSH ⚡` in the status bar — and `hostname` returning the container ID).
**Fix (host-side, one line):** in your host's `~/.ssh/config`, either drop the per-host `ControlPath` (to inherit the writable baked default) or point it at a path that's writable inside the container too:
```sshconfig
Host my-remote
# was: ControlPath ~/.ssh/cm/%r@%h:%p ← read-only in the container
ControlPath /tmp/sshcm/%r@%h:%p # writable on both host and container
```
`/tmp/sshcm/` is also writable on the host (macOS/Linux), so native (non-container) `ssh`/`pi --ssh` from the host keeps working and CGNAT multiplexing is preserved (`ControlMaster`/`ControlPersist` unchanged — only the socket *directory* moves). Note SSH does not create the `ControlPath` parent dir; the container makes `/tmp/sshcm` every start, but on the host run `mkdir -p /tmp/sshcm` once if it doesn't already exist.
### Custom opencode config
Opencode configuration is persisted automatically via the named volume `devbox-opencode-config`. This volume is mounted at `/home/developer/.config/opencode` by default — no host directory setup required. All changes to `opencode.jsonc`, skills, and (on the OMOS variant) `oh-my-opencode-slim.json` survive container recreation.