2b8c3a4db4ee5199b0f1b987e729330808bcda56
27 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
93f986e90e |
v1.8.6: adopt pi 0.84.3 + mempalace 3.8.0, close the v1.8.5 doc/observability gaps
Lint / hadolint (push) Successful in 9s
Publish Docker Image / resolve-versions (push) Successful in 15s
Publish Docker Image / base-decide (push) Successful in 8s
Lint / actionlint (push) Successful in 1m9s
Publish Docker Image / build-base (push) Successful in 41m23s
Publish Docker Image / smoke (push) Successful in 4m50s
Publish Docker Image / smoke-studio (push) Successful in 5m5s
Publish Docker Image / build-variant (push) Successful in 15m46s
Publish Docker Image / update-description (push) Successful in 7s
Publish Docker Image / promote-base-latest (push) Successful in 15s
Publish Docker Image / build-variant-studio (push) Successful in 19m59s
Three coupled pieces of work, all of which ride on the base rebuild that the
mempalace bump forces anyway.
DRIFT ADOPTED
- pi 0.84.2 -> 0.84.3. Its release notes carry a "Breaking Changes" line
(GoogleThinkingLevel -> GoogleApiThinkingLevel). Audited before adopting:
zero references across all four vendored companions (pi-fork,
pi-observational-memory, pi-atelier, pi-studio), so it is inert for us. The
reason to adopt is two skill-discovery fixes that land directly on v1.8.5's
vendored-skill work: nested Markdown skills inside grouping directories were
not discovered, and root README.md/AGENTS.md in skill dirs were reported as
broken skills.
- mempalace core 3.7.1 -> 3.8.0. Additive/reliability only. Its sync fix
(#2320/#2322) stops sync --apply deleting drawers whose source_file was
unreachable *at that moment* -- which does NOT relax the standing landmine
against sync on the shared palace, because that landmine is about paths
permanently absent from whichever host runs the sync. Different failure
shape; the caution stands.
DOCS -- three defects, one of them public
- DOCKER_HUB.md advertised "neovim (LazyVim defaults)". Nothing in the image
installs LazyVim; the only nvim config is a 19-line sysinit.vim. CI PATCHes
this file into the Docker Hub description on every release, so this was a
false claim published to the world. Removed.
- agent-browser + Playwright + Chromium is the single largest addition in the
image (~625 MB) and had zero mentions in README, DOCKER_HUB or THIRD_PARTY --
it was documented only to agents, in the AGENTS.md managed block. Now
documented to humans, including the Chromium licence dimension.
- typst and socat appeared in README prose but not in the "What's inside"
inventory. Added.
OBSERVABILITY -- the three gaps v1.8.5 listed as still open
- build-manifest.json now records mempalace core, read from the live binary
(ground truth, not the build ARG). Placed as a sibling of pi_version rather
than inside components{}, because pi-devbox-version renders that map through
[0:12] and would truncate a version string.
- smoke asserts the pi-observational-memory clone actually CONTAINS the ce9fc98
auth fix, pinned to src/runtime.ts. Deliberately not a repo-wide grep: two of
the three markers also live under tests/, so the repo-wide form stays green
with the fix site reverted. That is the third false-green of this exact family
in this repo (canary phrase in both snapshots; reconciler fixture using a
non-owned name; now this) -- pin containment checks to the fix site.
- smoke asserts the feeder's pi@<device> agent default behaviourally. The
earlier audit concluded this needed a --print-config added upstream; it does
not. AGENT is assigned before arg parsing, so `bash -x mempalace-pi-session
--help` observes the real resolution with no toolkit change. Two-sided:
device set => pi@<device>, unset => must not be pi@*.
- pi-devbox-version now prints a palace: line with the same live-vs-baked drift
detection pi already had. This matters more than it looks: mempalace is the
one component that is both client (here) and server (synlig), so skew between
them is a real failure mode. Degrades quietly on pre-v1.8.6 images.
Deferred deliberately: a native arm64 act_runner on tor-ms22 (the current
runner is on synlig, x86_64, so every arm64 layer ships QEMU-emulated).
Analysis and caveats filed to the palace rather than actioned here.
|
||
|
|
b5810654f6 |
skills: let the skillset own the skills it owns, and stop a dangling link from killing boot
Baked skill links won over the live skillset clone for all three vendored skills, so a pushed edit to skills/mempalace/SKILL.md was invisible in every container until the next image build -- measured on two hosts (live md5 129bcc4752 vs baked 5236024fef). Cause was ordering, not intent: the baked links are created early with a create-only-when-absent guard to close a smoke readiness race, and the skillset deploy runs last and treats them as foreign. The comment claimed the opposite of the behaviour. The fix is not "skillset always wins". Ownership is per-skill: pi-extensions is owned by its package repo and copied over the snapshot at build time, so the skillset's lagging duplicate must keep losing; pi-devbox-environment is authored here. Only mempalace is skillset-owned. devbox-skill-reconcile therefore runs after the deploy and repoints only the names in skills/skillset-owned.txt, replacing a link solely when it points into the baked tree, so a real directory or a link pointing elsewhere is never disturbed. Precedence is now user override -> live clone (owned names) -> baked snapshot, with the early links intact as the fallback so the readiness race stays closed. Reviewing that turned up a latent boot-abort in the pre-existing baked-link block: `[ ! -e "$link" ]` is TRUE for a dangling symlink, so once a link can point into /workspace/skillset, a vanished mount makes plain `ln -s` fail with "File exists" -- and under `set -euo pipefail` that aborts container start before `exec "$@"`. Reachable on `docker restart` or a host reboot, not on a recreate, since ~/.agents is not a volume on any host. Now `ln -sfn`, which heals the link back to the baked fallback. Smoke additions cover what let this ship: the stale-snapshot canary grepped a phrase present in BOTH the stale and fresh copies, so it passed throughout; it now pins the newest section. Link targets are asserted, not just `test -L`; the owned-list content is asserted both ways; and the reconciler's replace path -- which no CI container exercises, since none mounts a skillset -- is covered by fabricating one. A mutation test showed the obvious three assertions still pass with the "is this link ours?" guard deleted, so a discriminating case was added: an owned name whose link is a user override outside the baked tree. Also refreshes the mempalace snapshot to skillset 670f7f1 (without it the fix helps only hosts that mount skillset) and corrects README, which documented the old, wrong precedence in three places. Verified with 12 fixture cases plus 2 mutants: ownership respected against the real trees, user overrides preserved, relative/trailing-slash/CRLF/space/glob inputs handled, dangling link healed, read-only skills dir exits 0, idempotent. |
||
|
|
fbc1f86612 |
docs: a negative result is usually your own filter (skill + AGENTS.md)
Three false negatives in one session, all self-inflicted, all convincing because the command "succeeded": a `| head -20` proved an SSH peer absent that sits at line 454 of a ~500-line config; `ssh mac 'docker ps'` proved the host had no Docker, when the non-interactive PATH simply lacks /usr/local/bin; and `grep 'ssh '` proved no ControlMaster was running, when those processes rename themselves to `ssh: <path> [mux]`. Same root cause each time, so it goes in the skill rather than in a commit message: a positive result carries its own evidence, absence has to be earned. The skill (rootfs/, symlinked into ~/.agents/skills) is BAKED, so this is an image change and is logged in CHANGELOG Unreleased accordingly. Its §3 also now records that a live ControlMaster socket makes later commands authenticate not at all -- after editing a peer's authorized_keys, "it still works" proves nothing; prove it with -o ControlPath=none, or the breakage waits for a future session that has no memory of the edit. AGENTS.md: corrected a stale CI claim while placing the pointer. It said a tag push produces two runs including lint; lint.yml has since been scoped to branches: ['**'], which excludes tag refs, and refs/tags/v1.8.4 duly produced run 571 (publish) and nothing else. Kept the head_sha + workflow path filter advice, which is cheap and guards against a future v*-triggered workflow. Added a short section on verifying this repo from inside a container, including that docker-compose.yml here is a TEMPLATE pinning :latest while a real host runs its own per-machine file -- recreating from the repo copy can silently move a host off :latest-studio. Placement note: AGENTS.md is only auto-read when the cwd is this repo, so the durable rule lives in the skill, which loads by description match in any pi-devbox session. |
||
|
|
3a509077c2 |
v1.8.3: mempalace 3.7.1, refreshed skill snapshot, census on PATH
Lint / hadolint (push) Successful in 8s
Lint / actionlint (push) Successful in 23s
Publish Docker Image / resolve-versions (push) Successful in 13s
Publish Docker Image / base-decide (push) Successful in 11s
Publish Docker Image / build-base (push) Successful in 53m49s
Publish Docker Image / smoke (push) Successful in 7m22s
Publish Docker Image / smoke-studio (push) Successful in 18m6s
Publish Docker Image / build-variant (push) Successful in 19m6s
Publish Docker Image / update-description (push) Successful in 6s
Publish Docker Image / promote-base-latest (push) Successful in 11s
Publish Docker Image / build-variant-studio (push) Successful in 27m5s
mempalace 3.6.0 -> 3.7.1. Verified against the 3.7.1 source rather than its
changelog, because the risk lands on palaces users cannot reconstruct: legacy
drawers lack the new chunk_total marker and both decision sites trust them, so
no mass re-mine; NORMALIZE_VERSION is 2 in both; chromadb stays <2 so no
index-format migration; no auto-migration exists; logstream.sqlite3 is created
lazily. Downgrade remains possible (3.6.0 has zero references to chunk_total).
Two behaviour changes documented in the CHANGELOG: ALLOW_PEER_WRITER no longer
works on local/chroma palaces, and writer-lock setup failures fail closed.
Neither affects this image's MCP-server-plus-CLI-feeder pattern, which already
serialised on the same lock under 3.6.0 -- the upstream "process-lifetime
single-writer" entry describes tightened escape hatches, not a new lease.
The motivation is the shared central palace: 3.7.1 drops the stale chromadb
SharedSystemClient cache on reconnect (3.6.0 could let a stale in-memory HNSW
segment overwrite a peer's writes, "index count going backwards"), releases the
writer lease on SIGTERM/SIGHUP, and stops treating an interrupted mine as
complete. The fleet primary was upgraded to 3.7.1 and restarted before this tag,
because 3.7.1 refuses writes when the served library drifts and reconnect cannot
clear that. opencode-devbox still pins 3.6.0, so the lockstep is broken until it
cuts its own release.
Vendored mempalace skill snapshot refreshed to skillset 936fed8 (was 63f3bf5).
This closes a gap that had been invisible for two commits: ~/.agents/skills/
mempalace symlinks to the IMAGE-BAKED copy, entrypoint-user.sh creates that link
first, and the skillset deploy never clobbers an existing name -- so in a devbox
container the vendored snapshot always wins and editing skillset alone changes
nothing a container reads. Brings the multi-machine shared-palace section and
the hand-crafted-provenance guard.
pi-global-AGENTS.append.md already carried the three shared-palace damage rules
(
|
||
|
|
a55f6369b3 |
AGENTS.md: three damage-prevention rules for a shared central palace
The managed block already tells agents to load the mempalace skill, but said nothing about the palace being shared with other machines. Three failure modes observed tonight while onboarding tor-ms22's feeders, all of which do damage rather than merely confuse: - `mempalace sync` prunes drawers whose source files look gitignored, deleted or moved. On a central palace that describes most of the content, including every other machine's. Compounded by RFC-001 7.2: feeders now stage inside the palace root, so a scoped sync can delete the drawers it just filed. - A client-side timeout is not a failure. The palace is single-writer and one large mine blocks every client for minutes, so `[mempalace ext] feed (tick) failed: mine timed out after 30000ms` usually means the mine COMPLETED. Verified: drawers from a timed-out tick were present 35 s after the client gave up. A blind retry files a duplicate. - The `mempalace` CLI has zero references to MEMPALACE_REMOTE_URL, so it always opens a palace on local disk and can silently disagree with the MCP tools. Orientation depth stays in the skill; only damage-prevention belongs here, because this file is always read and the skill's later sections often are not. |
||
|
|
fa04d2083d |
docs(rootfs): re-sync pi-extensions skill snapshot (fork boundary mechanism)
Vendored floor snapshot re-synced from pi-extensions 98eb07b, which documents the mechanism behind fork boundary violations (full parent-transcript inheritance via index.ts:47) plus the corrected claims about tool restriction and narrative invention. CI resolves PI_EXTENSIONS_REF from main HEAD, so a normal build ships the package-owned copy; this keeps the committed floor identical so scripts/smoke-test.sh's cmp assertion holds either way. |
||
|
|
209f2c2f67 |
docs(rootfs): re-sync mempalace snapshot from skillset 63f3bf5
Closes the drift found in 4d4abd9's investigation: the Temporal grounding
guidance was authored straight into this vendored fallback (
|
||
|
|
4d4abd9a9f |
skill(pi-devbox-environment): resolve a skill symlink before editing it
~/.agents/skills/ lives in the ephemeral container layer and is rebuilt by
entrypoint-user.sh on every start from two sources, so an edit made through the
symlink may vanish on the next recreate. Adds to §1 (persistence tiers):
- `readlink -f ~/.agents/skills/<name>` as the first move, with a tier table:
resolves under /workspace/skillset → edit in place; resolves under
/usr/local/share/pi-devbox/skills → image layer, edit the canonical repo and
`sudo cp` to activate for the running session.
- Canonical owner per baked skill (pi-devbox-environment → this repo;
pi-extensions → the package repo's skill/, plus this repo's floor snapshot;
mempalace → the private skillset repo), pointing at VENDORED.md as
authoritative.
- The shadowing gotcha: image-baked links are created first and only when
absent, and deploy-skills.sh --prune-stale leaves foreign links alone, so for
a name present in BOTH sources the image copy wins and a skillset edit has no
effect in the container. Documented with the live example found while writing
this: the baked mempalace snapshot carries a Temporal grounding section
(
|
||
|
|
d5c5da3f6c |
docs(rootfs): refresh vendored pi-extensions skill snapshot
Sync the image-baked "floor" copy at
rootfs/usr/local/share/pi-devbox/skills/pi-extensions/SKILL.md with
pi-extensions e73cb9f, which documents package-registration forensics
(packages[] vs whole-file grep), that /reload suffices for a newly installed
package, and a fork-output caveat — the findings from the fork-guard bug fixed
in
|
||
|
|
6625d66f3a |
docs(agents): point the global AGENTS.md managed block at agent-browser
Discoverability follow-up to baking agent-browser into the base: agents won't reach for a browser they don't know they have (the exact gap that made this capability easy to miss). Add a short pointer section to the pi-devbox managed block — capability, the preset AGENT_BROWSER_EXECUTABLE_PATH, and `agent-browser skills get core --full` for the command set. Pointer only; depth stays in the skill. rootfs change → folds into the same base-<hash> rebuild. CHANGELOG note updated. |
||
|
|
71b12a9ed4 |
docs(skill): note macOS NFD-filename gotcha for dscp/scp
Accented filenames on a macOS host are stored decomposed (NFD), so a precomposed (NFC) remote path in scp/dscp silently fails with 'No such file or directory'. Document the wildcard / list-first workaround in the pi-devbox-environment skill, next to the dssh/dscp alias table. (Hit while copying a screenshot named 'Skärmavbild ….png' from the host.) |
||
|
|
fb49828826 |
base: add pi-devbox-version command + startup banner
Wraps /etc/pi-devbox/build-manifest.json (already written at docker-build time in Dockerfile.variant) into a human-readable summary instead of requiring users to know the manifest path and pipe it through jq themselves. - rootfs/usr/local/bin/pi-devbox-version: human (default) / --json / --quiet output modes. Also flags live drift — compares the baked pi_version against the actually-running `pi --version` and warns on mismatch rather than trusting the manifest blindly (same ground-truth philosophy as the manifest generation itself). Exits 1 with a short stderr notice on images built before the manifest existed, instead of failing silently. - entrypoint-user.sh: calls it as the very first line. CMD is `bash -l` with tty:true in compose, so this banner lands directly above the first prompt on container start — no separate motd/bashrc hook needed (deliberately not wired into .bash_aliases, which would reprint on every docker exec -it). - Dockerfile.base: COPY + chmod, same pattern as dot-watch/studio-expose. - scripts/smoke-test.sh: 4 new checks (binary present+executable, human output has release tag, --json round-trips the manifest, --quiet is a single line). - README.md / AGENTS.md / CHANGELOG.md updated. |
||
|
|
8c27894cf2 |
base: support modern terminals (ncurses-term + xterm-ghostty alias)
The base only shipped ncurses-base (xterm-256color, tmux), so SSHing in from WezTerm/Alacritty/foot/Ghostty degraded to a dumb TERM fallback. Following the maintainer's ansible common role: - Dockerfile.base: install ncurses-term (terminfo for wezterm, alacritty, foot, st, base ghostty entry, and many more). - rootfs/.../terminfo-src/ghostty.terminfo: thin xterm-ghostty alias (use=ghostty) — Ghostty connects as TERM=xterm-ghostty, which no distro packages. Compiled into the system db with 'tic -x'; build asserts it resolved via infocmp. - kitty (xterm-kitty) already covered by kitty-terminfo; iTerm2 uses xterm-256color (ncurses-base). - smoke-test: assert ncurses-term emulators + xterm-ghostty alias resolve. Validated end-to-end in a throwaway container: ncurses-term brings the entries, the alias compiles and equals the ghostty capability set. hadolint clean, bash -n OK. Base-affecting, rebuilds base-<hash>. No tag. |
||
|
|
aaf1be0bcb |
base: readable Neovim colours out of the box (termguicolors + kitty-terminfo)
Lint workflows / actionlint (push) Successful in 22s
Vanilla Neovim fell back to a 256-colour palette over ssh/kitty and rendered strings/comments in a muddy, low-contrast colour. Fix, all base-affecting: - rootfs/etc/xdg/nvim/sysinit.vim: system vimrc enabling termguicolors. Loads for every user before any personal ~/.config/nvim; overridable per-user. - Dockerfile.base: install kitty-terminfo (TERM=xterm-kitty understood; lets Neovim auto-detect true colour) and set ENV COLORTERM=truecolor. - smoke-test.sh: assert xterm-kitty terminfo present and nvim tgc default on. - CHANGELOG (Unreleased/Added) + README editor note. No tag — lands on the next base-<hash> rebuild. |
||
|
|
92212fa447 |
base: seed global gitignore with .claude/settings.local.json
Lint workflows / actionlint (push) Successful in 23s
Claude Code's per-machine local settings can carry credentials and should never be committed. Add the pattern to the seeded ~/.gitignore_global so fresh containers match a host global that already ignores it. Existing containers are unaffected (seed copied only when absent). Base-affecting; rebuilds base-<hash>. |
||
|
|
4563b4d76d |
feat: warn at shell startup if Mac host SSH is not reachable
Lint workflows / actionlint (push) Successful in 14s
Adds a _devbox_check_host_ssh() check to ~/.bash_aliases (baked into the image). On first bash session of each container it tries a quick SSH probe to the Mac host; if it fails it prints a clear one-time warning with the exact two steps needed to fix it: 1. Enable Remote Login in macOS System Settings 2. echo '<public key>' >> ~/.ssh/authorized_keys The check is guarded: - only runs inside a container (/.dockerenv) - only when the jump key exists (~/.ssh-local/devbox_jump_ed25519.pub) - only once per container lifetime (/tmp flag, cleared on recreate) After --force-recreate the key changes, the flag is gone, and the check runs again on the first bash window. Subsequent windows are silent. |
||
|
|
cc53877328 |
feat: bake global gitignore (core.excludesFile) into image
Seed ~/.gitignore_global from /etc/skel-devbox (seed-if-absent, like .bash_aliases/.inputrc, so user edits survive recreate) and wire it via git config --global core.excludesFile, guarded so a user-set excludesFile is never overridden. Ignores *.bak, *.bak.*, *~, *.orig, *.swp, *.tmp across all repos without per-repo .gitignore entries. |
||
|
|
904fe85249 |
skill(mempalace): teach temporal grounding (recreate != new day)
Baked mempalace SKILL.md now instructs agents to establish current date/time and compute the delta against the actual diary/drawer timestamp before using relative terms (yesterday/last week), and explicitly that a container recreate or fresh session is NOT a day boundary (pi-devbox restarts several times a day). Phase 1 wake-up section + anti-pattern bullet. CHANGELOG Unreleased. |
||
|
|
7551947466 |
feat(skills): add mempalace proactive-load directive for containers
Baking the mempalace fallback skill fixed *availability*, but mempalace had no proactive-load directive anywhere (pi-toolkit's global AGENTS.md only points to pi-extensions), so a new container would still surface it only via description-matching — the same under-utilisation the pi-extensions directive was created to fix. Add a session-start pointer to the pi-devbox managed AGENTS.md block (pi-global-AGENTS.append.md): gated to pi-devbox containers and conditional on the MemPalace MCP tools being present. Memory continuity matters most in a frequently-recreated container — the palace is its only cross-recreate memory. - pi-global-AGENTS.append.md: '## Session start: load the mempalace skill'. - smoke-test: assert the pointer merges into the global AGENTS.md at build. - docs: VENDORED.md, README, CHANGELOG [Unreleased]. Now both skills are complete in pi-devbox: directive + skill file. pi-extensions = directive (pi-toolkit) + baked skill; mempalace = directive (this block) + baked skill. |
||
|
|
a7d6a7d235 |
feat(skills): bake pi-extensions + mempalace fallback skills
The pi-toolkit global AGENTS.md tells every pi session to read
~/.agents/skills/pi-extensions/SKILL.md at start (the fork/recall
under-utilisation fix), but that skill lived only in the private skillset
repo — so the pointer dangled in any container started without skillset
mounted. Bake fallbacks so the pointer always resolves.
- pi-extensions (Option 1 + Option 2, layered):
* Canonical skill promoted to the public pi-extensions package repo under
skill/ (separate commit there); co-located with the code it documents.
* rootfs/ carries a committed snapshot (the floor).
* Dockerfile.variant copies /opt/pi-extensions/skill/ over the snapshot
after the pinned clone, so a normal build ships the fresh package copy
(recorded via PI_EXTENSIONS_REF) and an old-ref/mirror build still ships
the snapshot. Helper evaluate-extension-usage.py travels with it.
- mempalace (Option 2 only): snapshot in rootfs/. Its consumer skill has no
public package home (mempalace-toolkit ships a different skill,
opencode-mempalace-bridge), so no build-time refresh.
- entrypoint links both (only-when-absent; mounted skillset still wins).
- smoke-test: build-time presence + package-match check + runtime symlink
assertions; readiness gate now waits on the last-linked skill.
- docs: skills/VENDORED.md (provenance + refresh), README, AGENTS.md,
CHANGELOG [Unreleased].
Note: shipped in the NEXT release; v1.2.0 (run 409) predates this.
|
||
|
|
2abfee141b |
feat: image-baked agent skills + pi-devbox-environment skill (v1.2.0)
Publish Docker Image / resolve-versions (push) Successful in 35s
Publish Docker Image / base-decide (push) Successful in 23s
Publish Docker Image / build-base (push) Successful in 41m32s
Publish Docker Image / smoke-studio (push) Failing after 4m5s
Publish Docker Image / build-variant-studio (push) Has been skipped
Publish Docker Image / smoke (push) Failing after 5m46s
Publish Docker Image / build-variant (push) Has been skipped
Publish Docker Image / update-description (push) Has been skipped
Publish Docker Image / promote-base-latest (push) Has been skipped
Ship skills inside the image (independent of any mounted skillset repo): - rootfs/usr/local/share/pi-devbox/skills/<name>/ symlinked into ~/.agents/skills/ by entrypoint-user.sh (foreign-link, survives volume recreate, never clobbers a skillset/user skill of the same name). - New pi-devbox-environment skill: persistence model, host/LAN SSH reachability, split-DNS mechanisms, interactive-vs-tool-shell alias gotcha, tmux 0-index, uv-first Python, pi-studio reachability. Agnostic to host OS / hostnames / domains / nameservers (discovered at runtime). - Dockerfile.variant appends pi-global-AGENTS.append.md onto pi-toolkit's pi-global-AGENTS.md (single global slot) so the skill is loaded proactively; gated on /usr/local/lib/pi-devbox/. Idempotent. - smoke-test: baked-skill + append-snippet + merged-marker presence and a runtime symlink assertion. - docs: README 'Agent skills' section, AGENTS.md layout, DOCKER_HUB.md; moved studio-tex roadmap to v1.3.0. pi 0.79.7 -> 0.79.10 (auto-resolved from npm latest at build). |
||
|
|
8de0fad776 |
docs(lan): document ssh-lan.conf for naming LAN peers
The host-owned, bind-mounted ~/.config/devbox-shell/ssh-lan.conf is the intended place to add `ProxyJump host` overrides for named LAN peers (so `pi --ssh <peer>` / `dssh <peer>` route through the host), but it was only documented in .env.example and the setup-lan-access.sh header — never in the README, where someone hitting "can't reach LAN peers" actually looks. - README: add a "Naming LAN peers" subsection under the macOS LAN-peers troubleshooting block, with a ProxyJump example and the read-only ~/.ssh caveat; add a pointer to it from the SSH and ControlMaster section. - setup-lan-access.sh: correct the INCLUDE_BLOCK comment that suggested adding ProxyJump to the read-only ~/.ssh/config; point at ssh-lan.conf instead. - CHANGELOG: note under Unreleased. Docs/comment only — no behavior change. |
||
|
|
a0abacaafb |
fix(ssh): survive read-only ~/.ssh ControlPath; render sidecar on all host OSes
Publish Docker Image / smoke (push) Successful in 3m22s
Publish Docker Image / smoke-studio (push) Successful in 3m42s
Publish Docker Image / build-variant (push) Successful in 15m29s
Publish Docker Image / update-description (push) Successful in 11s
Publish Docker Image / build-variant-studio (push) Successful in 16m49s
Publish Docker Image / promote-base-latest (push) Successful in 14s
Publish Docker Image / resolve-versions (push) Successful in 8s
Publish Docker Image / base-decide (push) Successful in 8s
Publish Docker Image / build-base (push) Successful in 33m44s
Coordinated with the pi-extensions ssh-controlmaster fix (picked up at build via PI_EXTENSIONS_REF=main), this makes `pi --ssh <host>` and `dssh`/`dscp` robust to a user ~/.ssh/config whose per-host ControlPath points under the read-only ~/.ssh bind-mount (e.g. `ControlPath ~/.ssh/cm/%r@%h:%p`). A system default can never override a user's per-host value, so the fix lives in two layers. - setup-lan-access.sh: always render the writable ~/.ssh-local/config sidecar (Host * ControlPath redirect into ~/.ssh-local/cm + Include ~/.ssh/config) on EVERY host OS. Previously the script exited early (no-op) on native Linux, leaving dssh/dscp broken when ~/.ssh was read-only there too. The host-jump block, its key generation, and the authorize hints stay gated on VM-backed detection / DEVBOX_LAN_ACCESS=jump (new NEED_JUMP flag). - Dockerfile.base: document that the /etc/ssh drop-in default cannot override a user per-host ControlPath; cross-ref the two handling layers. - entrypoint-user.sh: correct the now-stale "no-op on native Linux" comment. - README.md / DOCKER_HUB.md: document read-only-~/.ssh ControlPath handling. CHANGELOG: v1.1.5 (Fixed + Changed + pi 0.79.6 -> 0.79.7 auto-resolved bump). |
||
|
|
5c08bfc8a8 |
fix(shell): don't export DEVBOX_HIST_SET so nested shells flush history
The history-flush guard was exported, so it leaked into child processes. Any nested shell -- crucially each tmux pane (which inherits the tmux server's env) -- then saw the guard already set and skipped installing 'history -a' in PROMPT_COMMAND. Those shells only persisted history on a clean exit, so abrupt termination (docker stop, tmux kill-server, SIGKILL) silently lost their in-memory history. zoxide was less affected (its hook is installed unguarded and writes immediately). Make the guard shell-local (drop 'export') so every new interactive shell re-installs its own per-prompt flush. Add a recreate-sanity-check assertion that a nested login shell still wires up 'history -a'. Storage was never the issue: ~/.cache/bash (devbox-shell-history) and ~/.local/share/zoxide (devbox-zoxide) are both persistent named volumes. |
||
|
|
ab5ff8ec56 |
feat: bundle dot-watch helper for live graphviz .dot -> PNG re-render in Studio
pi-studio renders Mermaid natively but has no DOT renderer. Its markdown preview displays local PNG/JPG/GIF/WEBP images, so dot-watch closes the loop for Graphviz: edit .dot -> auto-render <name>.png -> Studio refresh-from-disk shows the update. Uses mtime polling (no inotify dep). - rootfs/usr/local/bin/dot-watch: the helper (executable) - Dockerfile.base: COPY + chmod, following the studio-expose pattern - README.md: 'Graphviz diagrams in Studio' subsection - CHANGELOG.md: Unreleased entry graphviz was already in the base image; no new package. |
||
|
|
7d8ee4cea1 |
feat(studio): bundle studio-expose bridge + socat (opt-in STUDIO_EXPOSE)
pi-studio binds the container's 127.0.0.1, which a published Docker port can't reach. Add a robust, portable bridge rather than a doc-only one-liner: - Dockerfile.base: add socat (~1 MB, generally useful TCP relay). - rootfs/usr/local/bin/studio-expose: socat TCP relay listening on the container's egress IPv4 (not 0.0.0.0 — that would EADDRINUSE against Studio's loopback listener) forwarding to 127.0.0.1:PORT on the SAME port, so Studio's printed token URL works verbatim. Robust egress-IP detection (hostname -I, loopback-filtered; ip route get fallback), --help, port validation, foreground. - entrypoint-user.sh: opt-in STUDIO_EXPOSE=1 auto-starts the bridge in the background (studio variant only). Default OFF — Studio stays loopback-only (its secure default) unless explicitly opted in. - README: 'Using pi-studio' now documents host-networking (A) and the studio-expose/STUDIO_EXPOSE bridge (B) with a security note; ssh -L for remote, mosh caveat retained. - smoke-test: assert socat + studio-expose present (base-level). - CHANGELOG/AGENTS updated. No tag — stopping for review. |
||
|
|
c1154f1fa6 |
v1.0.0: decouple from opencode-devbox
Publish Docker Image / resolve-versions (push) Successful in 5s
Publish Docker Image / base-decide (push) Successful in 12s
Publish Docker Image / build-base (push) Successful in 45m47s
Publish Docker Image / smoke (push) Successful in 8m18s
Publish Docker Image / build-variant (push) Successful in 22m41s
Publish Docker Image / update-description (push) Failing after 9s
Publish Docker Image / promote-base-latest (push) Successful in 14s
Self-contained build chain — own Dockerfile.base + Dockerfile.variant
+ entrypoint scripts + rootfs + CI pipeline. Previously v0.79.0 and
earlier were thin re-brands of opencode-devbox's pi-only variant
(joakimp/pi-devbox:base-pi-only built by opencode-devbox CI).
Architectural changes:
- Replace 5-line Dockerfile shim with full base+variant pair.
- Adapt CI workflow from opencode-devbox/docker-publish-split.yml,
simplified to a single variant. Includes content-addressed base hash,
PI_VERSION concrete-resolution to defeat registry-buildcache footgun,
crane-based base-latest promotion, and the c6f9d11 smoke-test gate.
- pi-devbox releases no longer require rebuilding opencode-devbox first.
Base image additions:
- pandoc, graphviz, imagemagick, yq — broadly useful, ~260 MB total.
- tldr (tealdeer) — Rust port replaces Node tldr global, saves 135 MB.
- /etc/tmux.conf with base-index 0 + pane-base-index 0 — required for
the planned :latest-studio variant; pi-studio hard-codes :0.0 target.
Smoke test:
- New checks for pandoc, graphviz, imagemagick, yq, tldr, tmux config,
/tmp/sshcm directory.
- Image-size measurement now sums docker history layers (the prior
inspect --format='{{.Size}}' returned only the variant-unique layer
with the new base/variant split, understating by 2+ GB).
- Threshold 2850 → 3500 MB to absorb base additions + arch margin.
Image size:
- Local arm64 build: 3.20 GB. ~390 MB up from prior pi-only equivalent.
- Will tighten threshold once amd64 actuals settle in CI.
Pre-1.0 history preserved at tag pre-v1.0.0-decouple-backup.
Future work:
- v1.1.0: :latest-studio variant (adds pi-studio).
- v1.2.0: :latest-studio-tex variant (adds texlive-xetex for PDF).
- opencode-devbox v2.0.0 will retire INSTALL_PI / pi-only paths.
|