Files
opencode-devbox/CHANGELOG.md
T
joakimp 113c9f0bb0 Infrastructure pass: CI smoke tests, floating versions, chown sentinel, generate-config script
Main changes:

- Extract opencode.json generation from entrypoint-user.sh into a
  standalone Python script (rootfs/usr/local/lib/opencode-devbox/
  generate-config.py). Preserves the never-overwrite-existing-config
  guarantee. Cuts entrypoint-user.sh from 176 to 97 lines.

- Install MemPalace via 'uv tool install' into an isolated venv at
  /opt/uv-tools/mempalace/ with a /usr/local/bin/mempalace-mcp-server
  wrapper, replacing the 'pip install --break-system-packages' escape
  hatch. The wrapper is what generate-config.py references in the
  auto-generated opencode.json. Also fix 'mempalace init' in
  entrypoint-user.sh to use --yes so first-start initialization isn't
  interactive (this used to hang or print prompts into the user's
  terminal). Gated by INSTALL_MEMPALACE build arg (default true) so
  users who don't need AI memory can shave ~300 MB.

- Sentinel-file pattern in entrypoint.sh volume-ownership loop: write
  .devbox-owner after a successful chown -R, skip the recursive walk
  on subsequent starts when the sentinel matches FINAL_UID:FINAL_GID.
  Cuts multi-second startup costs to milliseconds on large volumes
  (nvim plugins, palace data). UID changes still trigger a full chown.

- Float all GitHub/Gitea-hosted binary versions: gosu, fzf, git-lfs,
  neovim, bat, eza, zoxide, uv, gitea-mcp now default to 'latest' and
  resolve the newest upstream release at build time via the /releases/
  latest redirect. Go (go.dev JSON feed) and oh-my-opencode-slim (npm
  @latest) likewise. Intentional pins still in place: OPENCODE_VERSION,
  NODE_VERSION=22, DEBIAN_VERSION=trixie-slim. Each *_VERSION ARG
  accepts an explicit value to lock a specific version when needed.

- New scripts/smoke-test.sh verifies binary presence, opencode startup,
  entrypoint user drop, generate-config idempotency, bun's presence-
  per-variant, and image size against thresholds (2500 MB base, 3000
  MB OMOS). Prints resolved component versions as its first step so
  CI logs always record what got baked into a given image.

- New .gitea/workflows/validate.yml runs on push to main and PRs:
  single-arch amd64 build, smoke test, DOCKER_HUB.md sync check. Tag-
  triggered docker-publish.yml now smoke-tests each variant on amd64
  before the full multi-arch push.

- scripts/generate-dockerhub-md.py auto-generates DOCKER_HUB.md from
  README.md using explicit SECTION_RULES. --check mode fails CI when
  the committed file is out of sync. Enforces the 25 kB Docker Hub
  limit. Adding a new README section forces an explicit keep/drop/
  replace decision.

- Remove dead INSTALL_PYTHON build arg (was a no-op since mempalace
  added python3 unconditionally).
2026-04-28 23:28:43 +02:00

12 KiB

Changelog

All notable changes to the opencode-devbox container image.

Tags follow v{opencode_version}[letter] — bare tag for the first build on a new opencode release, letter suffix (b, c, …) for container-level rebuilds on the same version. See AGENTS.md for details.


Unreleased

Infrastructure and maintainability pass.

  • Cleanup: Remove dead INSTALL_PYTHON build arg. Python 3 + pip + venv have been unconditionally installed in the base layer since mempalace was added; the flag was a no-op. Users should use uv (pre-installed) or uvx for Python tooling.
  • Fix: mempalace init in entrypoint-user.sh now uses --yes for non-interactive operation. Previously the command prompted the user (Your choice [enter/edit/add]:) on first container start, which either hung or printed prompts into the user's terminal. The init is still gated by [ ! -d "$PALACE_DIR/palace" ] so existing palace data from prior versions is preserved untouched on upgrade.
  • Feature: MemPalace is now installed via uv tool install into an isolated venv at /opt/uv-tools/mempalace/, reached through a new /usr/local/bin/mempalace-mcp-server wrapper. Replaces the previous pip install --break-system-packages approach — removes the PEP 668 workaround and keeps mempalace deps out of system Python site-packages. The wrapper is what generate-config.py now references in the auto-generated opencode.json. Users with custom opencode.json files should update their mempalace MCP command from ["python3", "-m", "mempalace.mcp_server"] to ["mempalace-mcp-server"].
  • Feature: New INSTALL_MEMPALACE build arg (default true). Rebuild with --build-arg INSTALL_MEMPALACE=false to shave ~300 MB off the image when local AI memory isn't needed.
  • Refactor: opencode.json generation extracted from entrypoint-user.sh into a standalone Python script at /usr/local/lib/opencode-devbox/generate-config.py. Easier to read, test, and extend with new providers. Default models are declared at the top of the script rather than hard-coded in bash heredocs. Reduces entrypoint-user.sh from 176 to 97 lines. Behavior is unchanged — the script preserves the critical guarantee of never overwriting an existing opencode.json.
  • Perf: Container startup avoids the recursive chown -R on named volumes that already have correct ownership. A .devbox-owner sentinel file written after a successful chown lets subsequent starts short-circuit via a single cat. On volumes with thousands of files (nvim plugins, palace data) this cuts multi-second startup costs to milliseconds. If USER_UID changes between runs, the sentinel mismatches and the full chown still runs.
  • CI: New validate workflow runs on every push to main and PR — single-arch amd64 build, smoke test, and DOCKER_HUB.md sync check. Catches broken Dockerfile changes without waiting for a tag push.
  • CI: docker-publish.yml now smoke-tests each variant on amd64 before the full multi-arch push. A failing smoke test blocks the release.
  • CI: Image size is tracked and fails the build if it exceeds thresholds (base: 2500 MB uncompressed, OMOS: 3000 MB). Makes bloat visible rather than silent.
  • Docs: DOCKER_HUB.md is now auto-generated from README.md via scripts/generate-dockerhub-md.py. Editing it directly is a mistake — the --check step in CI fails if the committed file is out of sync. Section inclusion is controlled by explicit rules (SECTION_RULES, TRIM_SUBSECTIONS); adding a new section to README forces an explicit keep/drop/replace decision. Keeps the 25 kB Docker Hub limit in sight and eliminates manual sync burden.
  • Tests: New scripts/smoke-test.sh asserts: (a) all core binaries are runnable and print a version, (b) opencode starts, (c) entrypoint correctly drops to the developer user, (d) generate-config.py produces valid JSON with the expected shape, (e) generate-config.py never overwrites an existing config, (f) bun is present only in the OMOS variant, (g) image size is under threshold. The smoke test also logs resolved versions of every component as its first step so CI output always records what got baked in.
  • Versioning: All GitHub/Gitea-hosted binaries (gosu, fzf, git-lfs, neovim, bat, eza, zoxide, uv, gitea-mcp) and the go.dev-hosted Go toolchain now default to latest at build time. Each *_VERSION ARG resolves the newest upstream release by reading the /releases/latest Location redirect (or the go.dev JSON feed). Previously these were hand-pinned to a specific version, which meant rebuilds didn't pick up upstream CVE fixes until someone remembered to bump the pin. Pinning is still supported — pass --build-arg NVIM_VERSION=0.12.1 etc. to lock a specific version. Intentionally still pinned: OPENCODE_VERSION (drives the image tag), NODE_VERSION=22 (major only), DEBIAN_VERSION=trixie-slim (OS base).

v1.14.28b — 2026-04-27

  • Feature: Add MemPalace local-first AI memory system to base image. Provides 29 MCP tools for semantic search over conversation history, knowledge graph queries, and agent diaries. Palace data persists via optional devbox-palace named volume, ChromaDB embedding model cache via devbox-chroma-cache. No API keys required.
  • Feature: Auto-register mempalace MCP server in generated opencode.json (when mempalace is installed and config is auto-generated from OPENCODE_PROVIDER).
  • Feature: Add official Gitea MCP server (gitea-mcp) to base image. Provides 50+ MCP tools for Gitea API (repos, issues, PRs, releases, Actions). Disabled by default — requires GITEA_ACCESS_TOKEN and GITEA_HOST env vars.

v1.14.28 — 2026-04-26

Bump opencode to 1.14.28.

v1.14.25 — 2026-04-25

Bump opencode to 1.14.25. Also includes container-level changes since v1.14.22b:

  • Add python3-pip and python3-venv to base image (fixes Mason LSP installs).
  • Add devbox-nvim-data named volume for neovim plugin/Mason persistence.
  • Add devbox-zoxide named volume for zoxide directory history persistence.
  • Bake devbox-shell bridge line into /etc/skel-devbox/.bash_aliases.
  • Add CHANGELOG.md with full release history.

v1.14.22b — 2026-04-23

Fix Mason LSP installs, persist nvim data, devbox-shell bridge.

  • Fix: Add python3-pip and python3-venv to base image. Mason creates a Python venv per LSP package and pip-installs into it; Debian trixie ships python3 without ensurepip, so venv creation failed and every Mason Python package (ruff, ansible-lint) errored on every nvim start.
  • Feature: Add devbox-nvim-data named volume at ~/.local/share/nvim — Lazy plugin cache and Mason LSP installs now persist across --force-recreate.
  • Feature: Add devbox-zoxide named volume at ~/.local/share/zoxide — zoxide directory history persists across recreates.
  • Feature: Bake the devbox-shell bridge line into /etc/skel-devbox/.bash_aliases — hosts using the ~/.config/devbox-shell/ directory-mount pattern get automatic sourcing without manual setup after recreate.

v1.14.22 — 2026-04-23

Bump opencode to 1.14.22.

v1.14.21 — 2026-04-23

Opencode 1.14.21 + zoxide persistence + multi-user fixes.

  • Bump opencode to 1.14.21.
  • Fix single-file bind-mount caveat: document the kernel-level inode issue (affects all platforms, not just Docker Desktop).
  • Pin project name in default docker-compose.yml — directory renames no longer orphan named volumes.
  • Fix volume collision in shared-machine compose: scope project name by SIGNUM.
  • Auto-detect OS username ($USER) for volume isolation in own-account mode.
  • Document the upgrade ritual for reconciling VM compose files.
  • Add multi-user setup pointer in DOCKER_HUB.md.

v1.14.20b — 2026-04-21

Fix [devbox] prompt marker lost on exec bash.

  • The PS1 prefix guard used an exported env var that survived exec bash, but PS1 itself doesn't — so the new shell skipped adding the prefix. Replaced with a substring check on PS1 itself.
  • Clarify tag-letter convention in AGENTS.md: suffix is the build ordinal, a is never used.

v1.14.20 — 2026-04-21

Opencode 1.14.20 + PROMPT_COMMAND/zoxide fix.

  • Bump opencode to 1.14.20.
  • Fix PROMPT_COMMAND collision with zoxide: history -a; followed by zoxide's ;__zoxide_hook produced ;; which bash rejected on every prompt. Moved history-flush after zoxide init, using newline separator.
  • Includes all v1.14.19c shell-defaults work (baked .bash_aliases/.inputrc via /etc/skel-devbox/, skel-copy on first run, devbox-shell-history named volume).

v1.14.19d — 2026-04-21

Superseded by v1.14.20 before building. Tagged but never built.

v1.14.19c — 2026-04-21

Bash history persistence, shell defaults, GID auto-detect.

  • Feature: Bash history persists across --force-recreate via devbox-shell-history named volume at ~/.cache/bash.
  • Feature: Quality-of-life shell defaults shipped in /etc/skel-devbox/ and copied to ~/ only if absent: prefix history search on Up/Down, 100k-entry timestamped dedup history, coloured case-insensitive tab completion, eza/bat aliases, zoxide/fzf integrations, [devbox] prompt marker.
  • Feature: Skel-copy pattern — host bind-mounts and in-container customizations are never overwritten on upgrade.
  • Fix: Entrypoint now detects workspace UID and GID independently. Hosts with UID 1000 but non-1000 GID (e.g. Debian's useradd default GID 1001) get correct group remapping.
  • Docs: SSH banner-timeout troubleshooting (CGNAT), shell defaults section, skel restore/diff commands.

v1.14.19b — 2026-04-20

Ownership fixes and config/docs refresh.

  • Fix: Root-owned parent dirs left behind by nested named-volume mounts. Entrypoint now chowns .local, .local/share, .local/state, .config before leaf mount points.
  • Fix: deploy/sync-to-vm.sh no longer preserves host GIDs (rsync -a-rlptDz).
  • Default model IDs refreshed (claude-sonnet-4-6, gpt-5.4, global Bedrock inference profile).
  • Documentation gates oh-my-opencode-slim references to the OMOS variant.

v1.14.19 — 2026-04-20

Bump opencode to 1.14.19.

v1.14.18 — 2026-04-19

Fix Bun download URL: remove non-existent LATEST file fetch.

v1.4.17 — 2026-04-19

Bump opencode to v1.4.17, add file utility to base image.

v1.4.12 — 2026-04-18

Bump opencode to v1.4.12.

v1.4.11 — 2026-04-18

Bump opencode to v1.4.11.

v1.4.7 — 2026-04-17

Bump opencode to v1.4.7.

v1.4.6 — 2026-04-15

Bump opencode to v1.4.6.

v1.4.3k — 2026-04-13

Fix Bedrock config: add AWS_PROFILE to generated config, add .agents/skills to volume ownership fix.

v1.4.3j — 2026-04-13

Upgrade base image from Debian bookworm to trixie (current stable). Bookworm EOL June 2026; trixie supported until 2028/LTS 2030.

v1.4.3i — 2026-04-12

Add rustup for on-demand Rust support, document JS/TS development.

v1.4.3h — 2026-04-12

Add uv package manager to base image for on-demand Python support.

v1.4.3g — 2026-04-12

Fix IPv6 connectivity failures: force IPv4 preference in CI builds.

v1.4.3f — 2026-04-11

Add error handling to Docker Hub description update step.

v1.4.3e — 2026-04-10

Fix CVEs: install git-lfs from GitHub (Go 1.25), document Go versions for gosu/fzf.

v1.4.3d — 2026-04-10

Fix CVEs: install gosu 1.19 and fzf 0.71.0 from GitHub releases instead of Debian packages.

v1.4.3c — 2026-04-10

Fix CVEs: install gosu from GitHub release instead of Debian package (Go 1.19.8 → current).

v1.4.3b — 2026-04-10

Fix entrypoint crash on read-only SSH mount.

v1.4.3 — 2026-04-10

Bump opencode to 1.4.3.

v1.4.2 — 2026-04-10

Initial release. Fix CI: use vars for username, secrets for token.