Commit Graph

12 Commits

Author SHA1 Message Date
joakimp d01cff38d5 DOCKER_HUB: add tailored pi section (run, mempalace, persistence)
Validate / docs-check (push) Successful in 12s
Validate / validate-base (push) Has started running
Validate / validate-omos (push) Has started running
Validate / validate-with-pi (push) Has been cancelled
Validate / validate-omos-with-pi (push) Has been cancelled
Hub readers had no signal at all about pi beyond the variant tag names
in the Image Variants table. The full README pi section is too large
to include verbatim (would push past 25 kB), so this adds a custom
`replace` rule in generate-dockerhub-md.py with a slimmed Hub-tailored
version covering the three things a Hub user actually needs:

  - Run: how to start pi via compose run / compose exec
  - MemPalace integration: shared palace with opencode, mempalace.ts
    bridge symlinked at first start
  - Persistence: which paths are on volumes, what survives --rm,
    upgrade path for the pi binary itself

Build args, extension list, and toolkit detail link out to the gitea
README anchor for users who want full reference.

DOCKER_HUB.md now 24862 bytes (138 byte headroom under the 25k limit).
2026-05-08 21:27:59 +02:00
joakimp 8083cd1a6f docs: surface with-pi and omos-with-pi variants on Docker Hub
Validate / docs-check (push) Successful in 14s
Validate / validate-base (push) Successful in 11m37s
Validate / validate-omos (push) Has been cancelled
Validate / validate-omos-with-pi (push) Has been cancelled
Validate / validate-with-pi (push) Has been cancelled
The v1.14.41b release expanded the CI matrix to four image variants
and pushed eight tags total, but the docs lagged behind:

- DOCKER_HUB.md's Image Variants table still listed only base + omos.
- README.md's pi section only described building from source; no
  mention that prebuilt latest-with-pi / latest-omos-with-pi tags
  exist (asymmetric vs the OMOS section which does mention latest-omos).

Fix:
- generate-dockerhub-md.py HEADER: extend Image Variants table to all
  four variants (base, omos, with-pi, omos-with-pi).
- README.md pi section: add a Setup subsection mentioning the prebuilt
  pi-enabled tags, mirroring the OMOS section's pattern.
- Regenerate DOCKER_HUB.md (22975 bytes, well under the 25k Hub limit).

The pi section itself remains intentionally dropped from DOCKER_HUB.md
to fit the 25k limit (SECTION_RULES); the Image Variants table at the
top is sufficient signal for Hub readers.
2026-05-08 21:14:01 +02:00
joakimp f46c4ed017 CI matrix: add with-pi and omos-with-pi build variants
Validate / docs-check (push) Successful in 39s
Validate / validate-base (push) Successful in 13m40s
Validate / validate-omos (push) Successful in 19m15s
Validate / validate-with-pi (push) Successful in 13m53s
Validate / validate-omos-with-pi (push) Successful in 18m26s
Publish Docker Image / smoke-base (push) Successful in 12m21s
Publish Docker Image / smoke-with-pi (push) Successful in 14m17s
Publish Docker Image / smoke-omos (push) Successful in 16m55s
Publish Docker Image / smoke-omos-with-pi (push) Successful in 16m22s
Publish Docker Image / build-base (push) Successful in 40m52s
Publish Docker Image / build-with-pi (push) Successful in 47m32s
Publish Docker Image / build-omos (push) Successful in 51m41s
Publish Docker Image / build-omos-with-pi (push) Successful in 56m44s
Publish Docker Image / update-description (push) Successful in 15s
.gitea/workflows/validate.yml:
  Adds validate-with-pi (INSTALL_PI=true) and validate-omos-with-pi
  (INSTALL_OMOS=true + INSTALL_PI=true). amd64 single-arch with smoke
  test, no push.

.gitea/workflows/docker-publish.yml:
  Adds smoke-with-pi → build-with-pi and smoke-omos-with-pi →
  build-omos-with-pi job pairs. Each push-by-digest multi-arch
  (amd64+arm64) to Docker Hub with two tags:
    ${VERSION}-with-pi      + latest-with-pi
    ${VERSION}-omos-with-pi + latest-omos-with-pi
  update-description.needs[] extended to wait on both new build jobs.

scripts/smoke-test.sh:
  bun-presence check now treats omos and omos-with-pi as the bun
  variants. Pi state assertions wait up to 30s for entrypoint-user.sh
  to finish deploying pi-toolkit + extensions (omos-with-pi has more
  setup work than the base+pi path; the previous sleep-1 was too short
  and caused empty-error assertion failures on cold starts).

Local verification (arm64 via OrbStack):
  base            → 1871 MB, all checks PASS
  omos            → 2813 MB, all checks PASS
  with-pi         → 2277 MB, all checks PASS
  omos-with-pi    → 3030 MB, all checks PASS

CI now produces 8 Docker Hub tags per release:
  vX.Y.Z[n], latest
  vX.Y.Z[n]-omos, latest-omos
  vX.Y.Z[n]-with-pi, latest-with-pi
  vX.Y.Z[n]-omos-with-pi, latest-omos-with-pi
2026-05-08 13:53:08 +02:00
joakimp f51e9f52a1 Add INSTALL_PI build arg for pi as second harness
Optional integration of pi-coding-agent alongside opencode in the same
container. Both harnesses share the mempalace install and palace path —
wing/diary entries are mutually visible.

Build:
  --build-arg INSTALL_PI=true              # opt-in
  --build-arg PI_VERSION=0.73.1            # pin a version (default: latest)
  --build-arg INSTALL_OPENCODE=false       # build pi-only image

Dockerfile:
  • New INSTALL_PI block: npm install -g @mariozechner/pi-coding-agent
    + git-clones pi-toolkit and pi-extensions to /opt/.
  • Existing opencode install gated behind new INSTALL_OPENCODE arg
    (default true; existing builds unaffected).
  • mkdir adds ~/.pi/agent/extensions for the named volume mount root.
  • CMD changed from ['opencode'] to ['bash', '-l']. compose run --rm
    devbox now drops to a login shell so users pick the harness; pass
    'opencode' or 'pi' explicitly to launch directly. compose exec
    workflows are unaffected (bypass entrypoint+CMD).

entrypoint.sh:
  • Adds ~/.pi to volume ownership loop.

entrypoint-user.sh:
  • New 'pi: deploy toolkit + extensions + mempalace bridge' block runs
    pi-toolkit/install.sh, pi-extensions/install.sh, settings.json
    template bootstrap, then symlinks the mempalace.ts bridge directly.
    Order: toolkit before extensions before bridge. mempalace-toolkit's
    full install.sh is intentionally NOT called (its install_skill
    would race with skillset auto-deploy --prune-stale).

docker-compose.yml:
  • New devbox-pi-config named volume mounted at /home/developer/.pi.
    Persists user toggles (/ext-disabled extensions) and settings.json
    edits across container recreate. Mirrors devbox-opencode-config
    pattern from v1.14.33.

scripts/smoke-test.sh:
  • New --variant with-pi (threshold 2700 MB) and --variant omos-with-pi
    (3400 MB).
  • Pi assertions gated on `command -v pi`: version, /opt/pi-toolkit
    clone HEAD, /opt/pi-extensions clone HEAD, deployed keybindings
    symlink, ≥4 extension symlinks, mempalace.ts bridge symlink,
    settings.json bootstrap.
  • Pi state assertions use docker exec from the host (not 'run'),
    since the container has no docker CLI.
  • opencode core test now gated on INSTALL_OPENCODE presence.

scripts/generate-dockerhub-md.py:
  • SECTION_RULES adds 'pi (alternative/complementary harness)': drop.
    Section stays in README; dropped from DOCKER_HUB.md to keep under
    the 25 kB Docker Hub limit.

Docs:
  • README adds full 'pi (alternative/complementary harness)' section.
  • AGENTS.md codifies pi install contract, deploy ordering, named
    volume rationale, and CMD change.
  • CHANGELOG.md gets an Unreleased entry.
  • .env.example documents new build args.
  • docker-compose.yml example args block updated.

Verification (local builds on arm64):
  • Default (INSTALL_PI=false): 1871 MB, all assertions pass — no
    regression.
  • INSTALL_PI=true: 2110 MB (within 2700 threshold), 37 assertions
    pass including pi version, all 7 extensions deployed (6 from
    pi-extensions + mempalace.ts bridge), settings.json bootstrap.

Not yet:
  • CI workflow updates to add -with-pi tag variants. Deferred until
    local path stabilizes through user testing.
  • pi-devbox separate repo for fully stripped pi-only image. Phase 2.
2026-05-07 23:58:37 +02:00
joakimp a803fe4653 Fix smoke-test JSONC parsing to respect URLs
Validate / docs-check (push) Successful in 20s
Validate / validate-base (push) Successful in 13m50s
Validate / validate-omos (push) Successful in 14m37s
Publish Docker Image / smoke-base (push) Successful in 12m14s
Publish Docker Image / smoke-omos (push) Successful in 12m52s
Publish Docker Image / build-base (push) Successful in 43m6s
Publish Docker Image / build-omos (push) Successful in 45m45s
Publish Docker Image / update-description (push) Successful in 13s
The previous 'sed "s|//.*$||"' approach greedily stripped '//' from
URLs like https://mcp.context7.com/mcp, corrupting the JSON and causing
smoke-test failures with json.decoder.JSONDecodeError. Replaced the sed
step with a Python regex that respects string literals so URLs pass
through while only line comments are removed.
2026-05-03 10:34:16 +02:00
Joakim Persson 3e3abc8672 Update docs for named volume config, skillset auto-deploy, opencode.jsonc
Validate / docs-check (push) Successful in 15s
Validate / validate-base (push) Failing after 10m35s
Validate / validate-omos (push) Failing after 13m15s
- README: rewrite config/skills sections for named volume and auto-deploy,
  add Context7 MCP docs, update all opencode.json→opencode.jsonc refs,
  add SKILLSET_CONTAINER_PATH to env var table
- CHANGELOG: add v1.14.32b entry documenting breaking changes and features
- AGENTS.md: update file roles, add skillset and config volume conventions
- DOCKER_HUB.md: regenerated (drop Context7 and Shell defaults sections
  to stay within 25KB Docker Hub limit)
- generate-dockerhub-md.py: add Context7 (drop) and Shell defaults (drop)
  to SECTION_RULES
2026-05-02 23:00:41 +00:00
Joakim Persson 3d4e739529 Add Context7 remote MCP server to auto-generated config
Validate / docs-check (push) Successful in 18s
Validate / validate-base (push) Failing after 11m26s
Validate / validate-omos (push) Failing after 13m14s
Context7 provides up-to-date library documentation for LLMs via a
remote endpoint — no local binary needed. Always registered since it
has no PATH dependency.

Also switches generated config from .json to .jsonc so we can include
a comment about the optional API key for higher rate limits. The
existing-config check now detects both file extensions.
2026-05-02 21:24:04 +00:00
Joakim Persson 5a2d06340e Fix dash-incompatible slash substitution and bump omos size threshold
Validate / docs-check (push) Successful in 18s
Validate / validate-base (push) Successful in 15m44s
Validate / validate-omos (push) Successful in 15m21s
Publish Docker Image / smoke-base (push) Successful in 14m30s
Publish Docker Image / smoke-omos (push) Successful in 15m51s
Publish Docker Image / build-base (linux/amd64) (push) Failing after 10m58s
Publish Docker Image / build-omos (linux/amd64) (push) Failing after 15m9s
Publish Docker Image / build-omos (linux/arm64) (push) Failing after 11m57s
Publish Docker Image / build-base (linux/arm64) (push) Failing after 39m30s
Publish Docker Image / merge-base (push) Has been skipped
Publish Docker Image / merge-omos (push) Has been skipped
Publish Docker Image / update-description (push) Has been skipped
v1.14.31b made it through smoke-base and validate-base (reclaim worked),
but two narrow bugs blocked the rest:

1. 'Derive platform slug' in the per-arch matrix jobs used bash
   ${PLATFORM_PAIR//\//-} which dash (/bin/sh in the runner) can't
   parse — 'Bad substitution'. Rewrote with 'tr / -'.

2. smoke-omos image size 3107 MB tripped the 3000 MB guardrail. All
   functional checks pass; the mempalace-toolkit bake-in from v1.14.30b
   added ~100 MB and the threshold was stale. Bumped to 3200 MB.

No image-level changes.
2026-05-01 10:43:04 +00:00
Joakim Persson 1683650240 Bake mempalace-toolkit wrappers into the image
Validate / docs-check (push) Successful in 14s
Validate / validate-base (push) Successful in 14m44s
Validate / validate-omos (push) Successful in 17m51s
Publish Docker Image / build-omos (push) Failing after 25m7s
Publish Docker Image / build-base (push) Failing after 55m51s
Publish Docker Image / update-description (push) Has been skipped
The scheduler templates in mempalace-toolkit's contrib/ assume
mempalace-session is available inside the container, but the image
never actually installed it. Users following the *-devbox scheduler
docs would silently lose the wrappers on every container recreate,
because the only way to get them was a post-hoc install.sh inside
the container — which lives in the ephemeral layer. The host-side
systemd timer would then fire, docker exec in, and hit
"mempalace-session: command not found".

Caught during runtime validation on 2026-04-30: host-side systemd
unit ran cleanly at 16:15 today, then the container was rebuilt
and recreated, and the wrappers were gone. The rebuild produced
an image that the scheduler template's own documented precondition
did not hold for.

Fix: new Dockerfile block clones mempalace-toolkit at build time
(depth-1) to /opt/mempalace-toolkit/, symlinks bin/mempalace-session
and bin/mempalace-docs into /usr/local/bin/, asserts both respond
to --help before the layer succeeds. Gated by
INSTALL_MEMPALACE_TOOLKIT=true (defaults on, depends on
INSTALL_MEMPALACE=true). Floated ref via MEMPALACE_TOOLKIT_REF=main
for auto-picking-up toolkit updates; override for reproducible
builds once the toolkit starts tagging releases.

Smoke test gains three assertions (mempalace-session --help,
mempalace-docs --help, symlink target check). Resolved-versions
preamble logs the toolkit git short-SHA alongside the other
floated components, so CI logs always record what got baked in.

README gains a Scheduled mining (mempalace-toolkit) subsection
and a build-args row. DOCKER_HUB.md regenerated; sync-check passes.
2026-04-30 20:56:58 +00:00
joakimp 23bae2ab7d Use mempalace-mcp entry point directly, drop redundant wrapper
Validate / docs-check (push) Successful in 20s
Validate / validate-base (push) Successful in 11m32s
Validate / validate-omos (push) Successful in 15m18s
Publish Docker Image / build-base (push) Successful in 53m5s
Publish Docker Image / build-omos (push) Successful in 1h11m3s
Publish Docker Image / update-description (push) Successful in 15s
The mempalace Python package ships a 'mempalace-mcp' console entry
point; 'uv tool install' places it on PATH as a shim whose shebang
points at the isolated venv's Python. Our hand-rolled wrapper at
/usr/local/bin/mempalace-mcp-server was duplicating what uv installs
for free — one less file to maintain.

Fixes the MCP error users saw after the v1.14.28b → v1.14.29 upgrade
path: custom opencode.json files typically had the pre-v1.14.29
command ['python3', '-m', 'mempalace.mcp_server'] which worked with
the old pip install but fails silently after the uv-tool migration
because system python3 cannot import from the venv. Opencode surfaced
this as 'MCP error -32000: connection closed'.

- generate-config.py now emits ['mempalace-mcp'] and keys its detect
  on shutil.which('mempalace-mcp').
- Dockerfile drops 'COPY rootfs/usr/local/bin/' and the chmod of the
  wrapper. Build shrinks from 30 to 29 stages.
- rootfs/usr/local/bin/ removed entirely.
- Smoke test asserts /usr/local/bin/mempalace-mcp is executable and
  prints its symlink target.
- README's MemPalace section shows ['mempalace-mcp'] and explicitly
  warns against the old pattern with the observed failure mode.
- CHANGELOG adds a v1.14.29c entry.
2026-04-29 15:27:30 +02:00
joakimp 349bb633ff Fix OMOS bunx detection
Validate / docs-check (push) Successful in 1m13s
Validate / validate-omos (push) Successful in 15m30s
Validate / validate-base (push) Successful in 17m11s
Publish Docker Image / build-omos (push) Failing after 14m43s
Publish Docker Image / update-description (push) Has been cancelled
Publish Docker Image / build-base (push) Has been cancelled
entrypoint-user.sh gated OMOS auto-install on 'command -v bunx', but
neither upstream bun installer nor our Dockerfile creates a bunx
symlink — only the bun binary exists on PATH. The check always failed
on a fresh OMOS image, printing 'ENABLE_OMOS=true but bun is not
installed.' even though bun was right there. Latent until now because
the only exercised path had a persisted oh-my-opencode-slim.json from
a prior install.

Fixes:
- Gate on 'command -v bun' instead of bunx.
- Call 'bun x oh-my-opencode-slim@latest install ...' (bun x is the
  real subcommand that actually works with only the bun binary).
- Add 'ln -sf bun /usr/local/bin/bunx' in the Dockerfile OMOS block
  so interactive users can still type bunx by habit.
- Smoke test asserts the bunx symlink exists on the OMOS variant.

Also verify 'test -L /usr/local/bin/bunx' as a build-time sanity check.
Can't use 'bunx --help' for that — bun exits 1 on help output even
though it prints the usage correctly.
2026-04-29 09:01:23 +02:00
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