Skip to content

Borrow three patterns from omaterm: release-asset install URL, mise SDKs, named home volume#80

Open
BrettKinny wants to merge 7 commits into
mainfrom
bootstrap-mise-volume
Open

Borrow three patterns from omaterm: release-asset install URL, mise SDKs, named home volume#80
BrettKinny wants to merge 7 commits into
mainfrom
bootstrap-mise-volume

Conversation

@BrettKinny
Copy link
Copy Markdown
Collaborator

@BrettKinny BrettKinny commented May 9, 2026

Summary

Four independent improvements inspired by reading omaterm, each on its own commit so they can be reverted independently:

  1. Release-asset install URLinstall.sh and install.ps1 ship as GitHub Release assets. The README quick-install URL points at releases/latest/download/install.sh, so pushes to main no longer affect new installs until a release is cut. (No bootstrap.sh shim — install.sh already self-bootstraps when curl-piped.)

  2. mise as the single SDK manager — drops nvm, astral.sh/uv, go.dev tarball, dotnet-install.sh, and rustup. ~/.config/mise/config.toml is now the source of truth; mise activate {bash,zsh,fish} wires shims onto PATH in all three shells. mise itself joins the Dockerfile-pinned tier (checksums.txt, ARG, sqrbx-update aware).

  3. Named volume for /home/dev — adds squarebox-home as a named Docker volume. Shell history, gh auth, claude-code state, and mise toolchains survive container recreates without the /workspace/.squarebox/gh kludge. Image-managed config (.bashrc extracted to dotfiles/bashrc) bind-mounts over the volume so repo updates flow through — same pattern starship.toml already used. setup.sh and motd.sh were relocated to /usr/local/lib/squarebox/ so they stay image-managed (Docker only seeds named volumes from the image at creation; anything in /home/dev/ would go stale across rebuilds).

  4. Recovery on top of the above — bumps microsoft/edit to .tar.gz (their v2.0.0 dropped the .tar.zst), and adds two guard assertions to the shell e2e suite so the stale-script regression class can't return.

Commits

5a24dd8 home: relocate setup.sh/motd.sh to /usr/local/lib/squarebox/
2025036 tools: bump microsoft/edit to .tar.gz (v2.0.0 upstream change)
942af86 docs/uninstall/test: align with mise + named-volume changes
ccfa222 sdk: replace nvm/uv/Go/.NET/rustup with mise
451ab54 home: back /home/dev with a named volume + bind-mounted bashrc
d7e7f50 ci: publish install.sh/install.ps1 as release assets

Behaviour changes worth knowing

  • First-run users are unaffected; the wizard UX is unchanged.
  • Existing users rebuilding will see a one-time gh re-auth (legacy /workspace/.squarebox/gh is migrated automatically on first run if no ~/.config/gh exists). Their old ~/.nvm, ~/.cargo, ~/.local/go directories live on harmlessly in the named volume but are no longer on PATH; re-running sqrbx-setup sdks re-installs cleanly via mise.
  • Disk: mise binary adds ~30 MB to the image. Per-SDK install size is similar to before. gpg and libatomic1 are now installed at the apt layer (mise needs gpg to verify Node release signatures; Node's official Linux binary needs libatomic1).
  • Trust model: SDK security now anchored to mise's pinning rather than each language's installer. Updated SECURITY.md trust table reflects this.
  • Scripts location: setup.sh and motd.sh now live at /usr/local/lib/squarebox/ (image-managed, root-owned, world-executable). Users who scripted against ~/setup.sh should switch to sqrbx-setup (which is the documented public entry point).

Test plan

  • docker build clean
  • e2e suites (local against squarebox:test): tools 11/11, shell 20/20 (incl. new 4.4/4.5 guards), setup 3/3, setup-editors 25/25, update 4/4, setup-rerun 7/7 — total 70/70.
  • bash -n clean across changed shell scripts
  • End-to-end persistence (manual): setup with sdks=node,gomise ls --current shows both → recreate container → marker file, history, mise config, node toolchain all persist
  • Bashrc bind mount: aliases (ls/cat/g), starship, MOTD load on first attach
  • AI-tool auto-install path (ensure_node_for_npm): Claude Code installs cleanly; Node provided on demand by mise
  • v0.9.0-rc1 tag pushed — verified release.yml runs and uploads install.sh + install.ps1 as prerelease assets. releases/download/v0.9.0-rc1/install.sh resolves.
  • Tag v0.9.0 (stable, no -rc) cut after merge — verifies releases/latest/download/install.sh resolves (GitHub's latest excludes prereleases, so an rc tag alone cannot satisfy the README URL).
  • CI shell/tools/setup/update suites green on the merge commit
  • arm64 build green on the merge tag
  • Manual sqrbx-uninstall --purge removes the named volume; default sqrbx-uninstall keeps it (sandboxed smoke locally: default keeps + --purge removes)

Notes for the merger

  • Cut v0.9.0 (no -rc) promptly after merge. The README's quick-install URL points at releases/latest/download/install.sh. GitHub's latest excludes prereleases, so the v0.9.0-rc1 we cut to smoke the workflow does not make the URL resolve — only a stable tag does. Until then, releases/latest/download/install.sh still redirects to v0.8.0, which 404s (v0.8.0 predates the asset publishing).
  • The unrelated demo/squarebox-setup-linkedin.gif was sitting untracked from before this branch and is not included in this PR (left as untracked locally).
  • Out of scope (deferred): squarebox.dev DNS for a prettier install URL; separating dotfiles into their own repo (omaterm's omadots pattern); cleanup of orphaned ~/.nvm/~/.cargo/~/.local/go in upgraders' named volumes.

🤖 Generated with Claude Code

BrettKinny and others added 4 commits May 9, 2026 21:45
Adds .github/workflows/release.yml so tagged releases (v*) attach
install.sh and install.ps1 to the GitHub Release. install.sh already
self-bootstraps when curl-piped (clones the repo, then runs from
there), so no separate bootstrap shim is needed.

Switch the README quick-install URLs from
raw.githubusercontent.com/.../main/install.sh (always serves HEAD)
to releases/latest/download/install.sh. Pushes to main no longer
break new installs until a release is cut.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switch /home/dev from in-image-only to the squarebox-home named Docker
volume. Shell history, GitHub CLI auth, claude-code data, and (in a
follow-up) mise toolchains now survive container recreates without the
/workspace/.squarebox kludge.

Image-managed config that previously lived inside the container -
.bashrc - is moved to dotfiles/bashrc in the repo and bind-mounted
read-only into /home/dev/.bashrc. The bind mount overrides the named
volume's copy at that sub-path (same pattern starship.toml and lazygit
already use), so repo updates propagate without touching user state.

gh auth: stop copying to /workspace/.squarebox/gh on every change. The
default ~/.config/gh location is now persistent via the named volume.
The legacy path is migrated once on first run for upgraders, then
ignored. The skip marker moves to ~/.squarebox-gh-skip.

Verified: docker build clean; container with squarebox-home volume +
bashrc bind mount loads aliases (ls/cat/g), starship, MOTD, and writes
to $HOME successfully.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drops five separate per-language installers (nvm, astral.sh/uv,
go.dev tarball, dotnet-install.sh, rustup) and the
~/.squarebox-sdk-paths shell-init kludge. mise now manages all SDKs
through ~/.config/mise/config.toml; `mise activate {bash,zsh,fish}`
in the relevant rc file wires shims onto PATH.

mise itself joins the Dockerfile-pinned tier (tools.yaml dockerfile
group, ARG MISE_VERSION, checksums.txt entry, sqrbx-update aware).
update-versions.sh now bumps MISE_VERSION alongside the others.

setup.sh: install_node/python/go/dotnet/rust collapse to thin wrappers
around _install_mise_sdk. ensure_node_for_npm uses mise too. Selection
flow (gum + /workspace/.squarebox/sdks) is unchanged so re-runs and
the AI-tools auto-Node path keep working.

Apt deps: gpg (for mise's signature verification of Node releases) and
libatomic1 (required by official Node Linux binaries) are now installed
unconditionally; the post-install gnupg purge is dropped since mise
needs it at runtime.

Verified end-to-end: setup.sh non-interactive run with sdks=node,go
installs both via mise; `mise ls --current` shows them; `node` and
`go` are on PATH after `mise activate bash --shims`. Build CI's tools
list and e2e-test's SDK assertions updated accordingly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After auditing the rest of the repo for stale references:

- e2e-test.sh: replace the ~/.squarebox-sdk-paths assertion (4.6d)
  with a check for `mise activate bash` in ~/.bashrc.
- CONTRIBUTING.md: drop nvm/Go from the optional-tools list and note
  that SDKs now ride on mise (Dockerfile-tier pinned).
- CLAUDE.md: SDK row in the first-run setup list now says "via mise";
  removed nvm/Go from the optional-tools paragraph.
- SECURITY.md: install URL points at the release asset; trust-model
  table swaps the per-SDK installer rows for a single mise row and
  bumps the binary-tools count to 9.
- uninstall.sh / uninstall.ps1: detect the squarebox-home named
  volume and remove it on --purge / -Purge (kept by default, parallel
  to ~/squarebox/workspace). Summary lines and "kept" hints updated.
- README "Uninstall" section: mention the named volume in --purge.

Verified: e2e suites shell (18/18), tools (11/11), setup (3/3),
update (4/4) all pass against squarebox:test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 9, 2026 12:12
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates squarebox’s installation and persistence model by (1) pinning quick-install entrypoints to GitHub Release assets, (2) consolidating language SDK management under mise, and (3) persisting /home/dev via a named Docker volume so user state survives container recreation.

Changes:

  • Switch README/SECURITY install URLs to releases/latest/download/install.{sh,ps1} and add a tag-triggered release workflow that publishes the install scripts as assets.
  • Replace per-language SDK installers (nvm/uv/go tarball/dotnet-install/rustup) with mise, and wire mise activate into bash/zsh/fish plus updater/version tooling.
  • Back /home/dev with a named volume (squarebox-home) and update install/uninstall + docs/tests accordingly.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
uninstall.sh Adds awareness/removal of the squarebox-home named volume on --purge.
uninstall.ps1 Windows equivalent named-volume detection/removal on -Purge.
setup.sh Migrates gh persistence logic + replaces SDK installation with mise.
SECURITY.md Updates install URL and trust-model documentation for release assets + mise.
scripts/update-versions.sh Extends Dockerfile-tier version bump automation to include mise.
scripts/squarebox-update.sh Adds mise to the in-container updater tool registry.
scripts/lib/tools.yaml Registers mise as a Dockerfile-tier pinned binary tool.
scripts/e2e-test.sh Updates E2E expectations for mise activation and SDK installation checks.
README.md Documents release-asset install URLs, mise-based SDKs, and named home volume persistence.
install.sh Mounts squarebox-home at /home/dev and bind-mounts repo-managed bashrc/config files.
install.ps1 Windows equivalent /home/dev named-volume + bashrc bind-mount.
dotfiles/bashrc New repo-managed bashrc that activates mise and triggers first-run setup.
Dockerfile Adds runtime deps for mise-managed SDKs, installs pinned mise, and copies new bashrc.
CONTRIBUTING.md Updates contributor guidance to reflect mise/SKD changes (some tool lists need refresh).
CLAUDE.md Updates project overview/docs for named volume + mise (some tool lists need refresh).
checksums.txt Adds vetted checksums for mise release artifacts (amd64/arm64).
.github/workflows/release.yml New workflow creating releases and uploading install scripts as assets on tags.
.github/workflows/build.yml Ensures mise exists in the base image during CI verification.
Comments suppressed due to low confidence (1)

install.ps1:191

  • Same /home/dev named-volume concern as install.sh: because sqrbx-setup runs ~/setup.sh, persisting /home/dev in a named volume can freeze setup.sh/motd.sh at whatever version first populated the volume. Bind-mount the repo’s setup.sh (and motd.sh) into /home/dev or relocate them outside the volume so upgrades take effect.
# --- Create container ---
Write-Host "Creating container..."

# Volume strategy: a single named volume backs /home/dev so shell history,
# claude-code state, mise toolchains, and gh auth survive container recreates.
# Bind mounts at sub-paths inside /home/dev override the volume - that's how
# we keep image-managed config (bashrc, starship.toml, lazygit) in lockstep
# with the repo while user state stays in the volume.
$homeVolume = if ($env:SQUAREBOX_HOME_VOLUME) { $env:SQUAREBOX_HOME_VOLUME } else { 'squarebox-home' }
$bashrcPath = Join-Path $InstallDir 'dotfiles\bashrc'

$rtVolumes = @(
    '-v', "$workspaceDir`:/workspace"
    '-v', "$homeVolume`:/home/dev"
    '-v', "${bashrcPath}:/home/dev/.bashrc:ro"
    '-v', "$gitCfgDir`:/home/dev/.config/git"
    '-v', "${starshipDest}:/home/dev/.config/starship.toml"
    '-v', "${lazygitDir}:/home/dev/.config/lazygit"
)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

zellij_current() { zellij --version 2>/dev/null | head -1 | awk '{print $2}' || echo "not installed"; }
just_current() { just --version 2>/dev/null | awk '{print $2}' || echo "not installed"; }
difftastic_current() { difft --version 2>/dev/null | head -1 | awk '{print $2}' || echo "not installed"; }
mise_current() { mise --version 2>/dev/null | awk '{print $1}' || echo "not installed"; }
Comment thread SECURITY.md
Comment on lines +47 to +48
| **install.sh** | Git repo from GitHub | HTTPS | Git transport verification | Tracks the latest tag (or `--edge` for `main`) |
| **bootstrap script** | `install.sh` itself, served as a release asset | HTTPS | Pinned to a tagged release; pushes to `main` don't affect new installs | Yes (tagged release) |
Comment thread install.sh
Comment on lines 398 to 412
echo "Creating container..."
RT_OPTS=()
# Volume strategy: a single named volume backs /home/dev so shell history,
# claude-code state, mise toolchains, and gh auth survive container recreates.
# Bind mounts at sub-paths inside /home/dev override the volume — that's how
# we keep image-managed config (bashrc, starship.toml, lazygit) in lockstep
# with the repo while user state stays in the volume.
HOME_VOLUME="${SQUAREBOX_HOME_VOLUME:-squarebox-home}"
RT_VOLUMES=(
-v "${INSTALL_DIR}/workspace:/workspace"
-v "${HOME_VOLUME}:/home/dev"
-v "${INSTALL_DIR}/dotfiles/bashrc:/home/dev/.bashrc:ro"
-v "${USER_HOME}/.config/git:/home/dev/.config/git"
-v "${INSTALL_DIR}/.config/starship.toml:/home/dev/.config/starship.toml"
-v "${INSTALL_DIR}/.config/lazygit:/home/dev/.config/lazygit"
Comment thread setup.sh
Comment on lines +176 to +183
# GitHub CLI config lives at ~/.config/gh (the gh default) and is preserved
# by the squarebox-home named volume. The legacy persistence path
# (/workspace/.squarebox/gh) is migrated once for users upgrading from a
# pre-named-volume install; new installs never touch it.
GH_PERSIST_LEGACY="/workspace/.squarebox/gh"
GH_SKIP_MARKER="$HOME/.squarebox-gh-skip"
GH_SKIP_MARKER_LEGACY="/workspace/.squarebox/gh-skip"
if [ -d "$GH_PERSIST_LEGACY" ] && [ ! -d ~/.config/gh ]; then
Comment thread CLAUDE.md
@@ -79,7 +83,7 @@ sqrbx-update

`scripts/update-versions.sh` only touches the Dockerfile tier (delta, yq, xh, glow, gum, starship, just, difftastic). It fetches latest GitHub releases, downloads artifacts for both architectures, computes SHA256 checksums, and updates `checksums.txt` and the Dockerfile ARGs.
Comment thread CONTRIBUTING.md
Comment on lines +78 to +85
Optional tools (editors, TUIs, opencode, zellij) track upstream latest at
install time. To add a new optional tool, add an entry to
`scripts/lib/tools.yaml` and call `sb_install <tool> latest` from `setup.sh`.
No checksum file update is required.

SDKs (Node, Python, Go, .NET, Rust) are installed by mise itself, which is
part of the Dockerfile-pinned tier — so SDK availability is gated by mise's
own pinning, not the SDK installers individually.
BrettKinny and others added 2 commits May 26, 2026 20:01
microsoft/edit v2.0.0 shipped its Linux release as a .tar.gz instead of
the previous .tar.zst. The old artifact suffix now 404s, which was
breaking the setup-editors-sdks e2e suite (3.7c edit installed). The
tar.gz handler in tool-lib.sh is already used by 12 other tools, so no
library changes are needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixes a stale-script regression introduced by backing /home/dev with a
named volume. Docker only seeds named volumes from the image the first
time the volume is created; subsequent rebuilds against the same volume
do not refresh files inside it. setup.sh and motd.sh previously shipped
into /home/dev/, so a returning user who ran sqrbx-rebuild then
sqrbx-setup would silently invoke the OLD setup.sh baked into their
volume on first install — every future setup.sh change would be
invisible to existing users.

Move both files alongside the other image-managed code under
/usr/local/lib/squarebox/ (next to tools.yaml and tool-lib.sh).
/home/dev/ now holds only user state; image-managed behaviour lives
outside the volume and is always fresh after a rebuild.

Invocation sites updated:
- dotfiles/bashrc: first-run setup + motd hand-off
- scripts/squarebox-setup.sh: --rerun invocation
- setup.sh: motd lines in the zsh and fish rc templates
- scripts/e2e-test.sh: five test invocations
- README.md: devcontainer hint now points at sqrbx-setup (the public entry)
- uat-checklist.md: same

Adds two guard tests in the shell suite (4.4, 4.5) asserting
/home/dev/setup.sh and /home/dev/motd.sh do not exist — structurally
prevents the regression class from returning.

Verified e2e: tools 11/11, shell 20/20 (incl. new guards),
setup 3/3, setup-editors 25/25, update 4/4, setup-rerun 7/7.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@BrettKinny BrettKinny closed this May 26, 2026
@BrettKinny BrettKinny reopened this May 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants