Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: All tools exist
run: |
docker run --rm squarebox:test bash -c '
for cmd in bat curl delta difft eza fd fzf gh glow gum jq just nano rg starship xh yq zoxide; do
for cmd in bat curl delta difft eza fd fzf gh glow gum jq just mise nano rg starship xh yq zoxide; do
which "$cmd" || { echo "MISSING: $cmd"; exit 1; }
done
'
Expand Down
39 changes: 39 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Release

on:
push:
tags:
- 'v*'

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Create release with install scripts as assets
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"

# Pre-release tags carry an `-rc`, `-beta`, etc. suffix.
prerelease_flag=""
case "$tag" in
*-*) prerelease_flag="--prerelease" ;;
esac

# Idempotent: if the workflow re-runs on the same tag, replace assets.
if gh release view "$tag" >/dev/null 2>&1; then
gh release upload "$tag" install.sh install.ps1 --clobber
else
gh release create "$tag" \
--title "$tag" \
--generate-notes \
$prerelease_flag \
install.sh install.ps1
fi
10 changes: 7 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

squarebox is a containerized development environment (Docker or Podman) combining modern CLI/TUI tools with Claude Code. It uses a persistent container model — the container suspends on exit and resumes on restart, preserving state. Workspace code lives on the host at `~/squarebox/workspace` via volume mount.
squarebox is a containerized development environment (Docker or Podman) combining modern CLI/TUI tools with Claude Code. It uses a persistent container model — the container suspends on exit and resumes on restart, preserving state. Workspace code lives on the host at `~/squarebox/workspace` via bind mount; per-user state (shell history, gh auth, claude-code data, mise toolchains) lives in the `squarebox-home` named Docker volume; image-managed config (`.bashrc`, `starship.toml`, `lazygit/`) is bind-mounted from `~/squarebox/dotfiles` so repo updates flow through.

## Build & Run

Expand All @@ -21,6 +21,8 @@ docker run -it --name squarebox \
-v ~/.ssh/config:/home/dev/.ssh/config:ro \
-v ~/.ssh/known_hosts:/home/dev/.ssh/known_hosts:ro \
-v ~/squarebox/workspace:/workspace \
-v squarebox-home:/home/dev \
-v ~/squarebox/dotfiles/bashrc:/home/dev/.bashrc:ro \
-v ~/.config/git:/home/dev/.config/git \
-v ~/squarebox/.config/starship.toml:/home/dev/.config/starship.toml \
-v ~/squarebox/.config/lazygit:/home/dev/.config/lazygit \
Expand All @@ -31,6 +33,8 @@ docker run -it --name squarebox \
docker start -ai squarebox
```

The `squarebox-home` named volume holds per-user state. Bind mounts at sub-paths inside `/home/dev` (`.bashrc`, `.config/starship.toml`, `.config/lazygit`, `.config/git`) override the volume so repo-managed files stay in lockstep with the image.

Replace `docker` with `podman` above if using Podman. The `install.sh` script auto-detects the runtime; override with `SQUAREBOX_RUNTIME=docker|podman`.

The `install.sh` script automates initial setup (clone, build, create container, add `sqrbx` shell alias). A `.devcontainer/devcontainer.json` is also provided for VS Code Dev Containers / Codespaces.
Expand All @@ -47,7 +51,7 @@ The `install.sh` script automates initial setup (clone, build, create container,
4. **Text editors** — micro, edit (Microsoft), fresh, nvim (nano is always available)
5. **TUI tools** — lazygit, gh-dash, yazi (any combination)
6. **Terminal multiplexers** — tmux, zellij
7. **SDKs** — Node.js (via nvm), Python (via uv), Go, .NET, Rust (via rustup)
7. **SDKs** — Node.js, Python, Go, .NET, Rust (all installed and managed by [mise](https://github.com/jdx/mise) via `~/.config/mise/config.toml`)
8. **Shell** — bash (default) or zsh + Oh My Zsh + autosuggestions + syntax highlighting (experimental)

Selections are saved to `/workspace/.squarebox/` and reused on subsequent rebuilds.
Expand Down Expand Up @@ -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.

Optional tools installed by `setup.sh` (opencode, editors, TUIs, zellij, Go, nvm) are not pinned. They install the latest upstream release at setup time, so there is no checksum file or version variable to update in the repo.
Optional tools installed by `setup.sh` (opencode, editors, TUIs, zellij) are not pinned. They install the latest upstream release at setup time, so there is no checksum file or version variable to update in the repo. SDKs are installed by mise (a Dockerfile-tier pinned binary), so SDK trust is anchored to mise's own pinning rather than per-language installers.

## CI

Expand Down
8 changes: 6 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,15 @@ Dockerfile-tier tools (delta, yq, xh, glow, gum, starship, just, difftastic) are
2. Review the diff. Verify version bumps and checksums look correct.
3. Rebuild and test.

Optional tools (editors, TUIs, opencode, zellij, Go, nvm) track upstream
latest at install time. To add a new optional tool, add an entry to
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.
Comment on lines +78 to +85

Never skip checksum verification for the Dockerfile tier.

### Style
Expand Down
73 changes: 16 additions & 57 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
toilet-fonts \
libicu-dev \
locales \
# Runtime deps for mise-managed SDKs:
# gpg — mise verifies upstream signatures (Node, etc.)
# libatomic1 — required by official Node Linux builds
gpg \
libatomic1 \
&& sed -i '/en_US.UTF-8/s/^# //' /etc/locale.gen \
&& locale-gen \
&& rm -rf /var/lib/apt/lists/* \
Expand All @@ -41,6 +46,7 @@ ARG GLOW_VERSION=2.1.2
ARG GUM_VERSION=0.17.0
ARG JUST_VERSION=1.49.0
ARG DIFFTASTIC_VERSION=0.68.0
ARG MISE_VERSION=2026.5.4

# Validate version ARGs are non-empty
RUN test -n "$DELTA_VERSION" || { echo "Error: DELTA_VERSION is empty" >&2; exit 1; } \
Expand All @@ -50,7 +56,8 @@ RUN test -n "$DELTA_VERSION" || { echo "Error: DELTA_VERSION is empty" >&2
&& test -n "$GLOW_VERSION" || { echo "Error: GLOW_VERSION is empty" >&2; exit 1; } \
&& test -n "$GUM_VERSION" || { echo "Error: GUM_VERSION is empty" >&2; exit 1; } \
&& test -n "$JUST_VERSION" || { echo "Error: JUST_VERSION is empty" >&2; exit 1; } \
&& test -n "$DIFFTASTIC_VERSION" || { echo "Error: DIFFTASTIC_VERSION is empty" >&2; exit 1; }
&& test -n "$DIFFTASTIC_VERSION" || { echo "Error: DIFFTASTIC_VERSION is empty" >&2; exit 1; } \
&& test -n "$MISE_VERSION" || { echo "Error: MISE_VERSION is empty" >&2; exit 1; }

# Checksum verification infrastructure
COPY checksums.txt /tmp/checksums.txt
Expand All @@ -77,8 +84,8 @@ RUN mkdir -p -m 755 /etc/apt/keyrings \
# Install from repos
&& apt-get update \
&& apt-get install -y --no-install-recommends gh eza \
# Purge build-only dependency
&& apt-get purge -y --auto-remove gnupg \
# Note: gnupg is kept (also installed in layer 1 as `gpg`) — mise needs it
# at runtime to verify Node release signatures.
&& rm -rf /var/lib/apt/lists/*

# Build-time tool install helper: sources library + wires up checksum verification
Expand All @@ -93,6 +100,7 @@ RUN . /tmp/sb-init.sh && sb_install gum "$GUM_VERSION"
RUN . /tmp/sb-init.sh && sb_install starship "$STARSHIP_VERSION"
RUN . /tmp/sb-init.sh && sb_install just "$JUST_VERSION"
RUN . /tmp/sb-init.sh && sb_install difftastic "$DIFFTASTIC_VERSION"
RUN . /tmp/sb-init.sh && sb_install mise "$MISE_VERSION"

# Clean up build-time files
RUN rm -f /tmp/checksums.txt /tmp/tools.yaml /tmp/tool-lib.sh /tmp/sb-init.sh
Expand Down Expand Up @@ -132,61 +140,12 @@ ENV HOME=/home/dev
ENV SQUAREBOX=1

# 7. Shell Config
# The .bashrc lives in dotfiles/ on the host so install.sh can bind-mount it
# into the container — keeping it in sync with the repo while shell history
# and per-user state stay in the squarebox-home named volume. The COPY here
# is what seeds a fresh volume; subsequent runs see the bind-mounted version.

RUN cat <<'EOFRC' >> ~/.bashrc
eval "$(starship init bash)"
eval "$(zoxide init bash --cmd cd)"
alias ls='eza --icons'
alias ll='eza -la --icons'
alias lsa='ls -a'
alias lt='eza --tree --level=2 --long --icons --git'
alias lta='lt -a'
alias cat='bat --paging=never'
alias ff="fzf --preview 'bat --style=numbers --color=always {}'"
alias eff='$EDITOR "$(ff)"'
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
export EDITOR='nano'
[ -f ~/.squarebox-ai-aliases ] && source ~/.squarebox-ai-aliases
[ -f ~/.squarebox-editor-aliases ] && source ~/.squarebox-editor-aliases
[ -f ~/.squarebox-tui-aliases ] && source ~/.squarebox-tui-aliases
[ -f ~/.squarebox-sdk-paths ] && source ~/.squarebox-sdk-paths
alias g='git'
alias gcm='git commit -m'
alias gcam='git commit -a -m'
alias gcad='git commit -a --amend'
export PATH="$HOME/.local/bin:$PATH"
# First-run setup
if [ ! -f ~/.squarebox-setup-done ]; then
if [ -n "${DEVCONTAINER:-}" ]; then
touch ~/.squarebox-setup-done
else
~/setup.sh && touch ~/.squarebox-setup-done
[ -f ~/.squarebox-ai-aliases ] && source ~/.squarebox-ai-aliases
[ -f ~/.squarebox-editor-aliases ] && source ~/.squarebox-editor-aliases
[ -f ~/.squarebox-tui-aliases ] && source ~/.squarebox-tui-aliases
[ -f ~/.squarebox-sdk-paths ] && source ~/.squarebox-sdk-paths
fi
fi
# Hand off to zsh if the user opted in via setup.sh (experimental).
# SQUAREBOX_IN_ZSH guards against re-exec loops; SQUAREBOX_NO_ZSH lets
# users force bash for one shell without removing the marker.
if [ -f ~/.squarebox-use-zsh ] && [ -z "${SQUAREBOX_IN_ZSH:-}" ] && [ -z "${SQUAREBOX_NO_ZSH:-}" ] && command -v zsh >/dev/null 2>&1; then
export SQUAREBOX_IN_ZSH=1
exec zsh -l
fi
# Hand off to fish if the user opted in via setup.sh (experimental).
# SQUAREBOX_IN_FISH guards against re-exec loops; SQUAREBOX_NO_FISH lets
# users force bash for one shell without removing the marker.
if [ -f ~/.squarebox-use-fish ] && [ -z "${SQUAREBOX_IN_FISH:-}" ] && [ -z "${SQUAREBOX_NO_FISH:-}" ] && command -v fish >/dev/null 2>&1; then
export SQUAREBOX_IN_FISH=1
exec fish -l
fi
EOFRC

# Display MOTD on interactive shell login
RUN echo '~/motd.sh' >> ~/.bashrc
COPY --chown=dev:dev dotfiles/bashrc /home/dev/.bashrc

WORKDIR /workspace
CMD ["/bin/bash"]
77 changes: 43 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ assistant, and language SDKs.

**Stable**

curl -fsSL https://raw.githubusercontent.com/SquareWaveSystems/squarebox/main/install.sh | bash
curl -fsSL https://github.com/SquareWaveSystems/squarebox/releases/latest/download/install.sh | bash

**Edge**

curl -fsSL https://raw.githubusercontent.com/SquareWaveSystems/squarebox/main/install.sh | bash -s -- --edge
curl -fsSL https://github.com/SquareWaveSystems/squarebox/releases/latest/download/install.sh | bash -s -- --edge

Stable installs the latest tagged release (pre-release tags like `-rc` are skipped). Edge uses the latest commit on main.
Stable installs the latest tagged release (pre-release tags like `-rc` are skipped). Edge uses the latest commit on main. The install script itself is published as a release asset, so the URL is pinned to a tagged version of the script — pushes to `main` won't break new installs until a release is cut.

If the install fails or you want to see the full docker build and git output, re-run with `--verbose`.

Expand All @@ -80,7 +80,7 @@ Windows users can install directly from PowerShell - no Git Bash required.
This handles clone, build, container creation, and PowerShell aliases
(`sqrbx`, `squarebox`, etc.) natively:

irm https://raw.githubusercontent.com/SquareWaveSystems/squarebox/main/install.ps1 | iex
irm https://github.com/SquareWaveSystems/squarebox/releases/latest/download/install.ps1 | iex

Once installed, you can re-run or pass flags from the local copy:

Expand All @@ -103,9 +103,11 @@ PowerShell 7+.

The container is persistent: it suspends on exit and resumes on start, keeping
installed packages, config, and shell history intact between sessions. Your
code and tool config live on the host under `~/squarebox` (`workspace/` for
code, `.config/` for tool config) via volume mounts, so they survive even if
the container is deleted.
code lives on the host at `~/squarebox/workspace` (bind-mounted), and per-user
state — shell history, GitHub CLI auth, claude-code data, mise toolchains —
lives in a named Docker volume (`squarebox-home`) that survives container
recreation. Image-managed config like `.bashrc` is bind-mounted from the repo
so updates flow through to the running container.

What's included
---------------
Expand Down Expand Up @@ -212,19 +214,23 @@ AI/editor/TUI/SDK selections are translated from their bash files into
> Set `SQUAREBOX_NO_ZSH=1` or `SQUAREBOX_NO_FISH=1` to force bash for a single
> session, or re-run `sqrbx-setup shell` to switch back permanently. Tooling
> is primarily tested against bash, so a few edge cases may need polish —
> please file an issue if you hit one. Known fish limitation: nvm (Node.js)
> is not wired into fish; install [nvm.fish](https://github.com/jorgebucaran/nvm.fish)
> separately if you need it.
> please file an issue if you hit one. SDK shims are wired into all three
> shells via `mise activate {bash,zsh,fish}`.

### SDKs

| SDK | Installed via |
|-----|---------------|
| Node.js | [nvm](https://github.com/nvm-sh/nvm) |
| Python | [uv](https://github.com/astral-sh/uv) |
| Go | [go.dev](https://go.dev) |
| .NET | [dotnet-install](https://dot.net) |
| Rust | [rustup](https://rustup.rs) |
All SDKs are managed by [mise](https://github.com/jdx/mise) — a single
polyglot version manager. Selections are written to `~/.config/mise/config.toml`
and `mise activate` wires up shims and PATH automatically across bash, zsh,
and fish.

| SDK | mise tool |
|-------|-----------|
| Node.js | `node` |
| Python | `python` |
| Go | `go` |
| .NET | `dotnet` |
| Rust | `rust` |

Aliases
-------
Expand Down Expand Up @@ -290,22 +296,23 @@ preserved.
sqrbx-rebuild

Pulls the latest changes, rebuilds the image, and replaces the container.
Your code in ~/squarebox/workspace is safe since it lives on the host.
Setup selections (AI tool, editors, SDKs, GitHub auth) are persisted in the
workspace volume and restored automatically. However, shell history, manually
installed packages, and custom config files inside the container are lost.
Your code in ~/squarebox/workspace is safe since it lives on the host. Most
in-container state (shell history, GitHub auth, SDK toolchains) survives
because /home/dev is backed by the `squarebox-home` named Docker volume.
Manually installed apt packages are still lost, since the image is rebuilt.

#### What survives a rebuild

| Survives | Lost |
|----------|------|
| Code in ~/squarebox/workspace (host volume) | Shell history (~/.bash_history) |
| Starship and lazygit config (host volume) | Manually installed apt packages |
| AI tool / editor / SDK selections | Custom dotfiles in /home/dev/ |
| GitHub CLI auth | Caches and temp files |
| Code in ~/squarebox/workspace (host bind mount) | Manually installed apt packages |
| /home/dev (squarebox-home named volume): shell history, GitHub CLI auth, claude-code data, mise toolchains | |
| Starship, lazygit, .bashrc (bind-mounted from repo, picks up updates) | |
| AI tool / editor / SDK selections (in /workspace/.squarebox) | |
| SSH keys (on host, forwarded via agent) | |

To preserve extra files across rebuilds, store them in `/workspace/.squarebox/`.
To wipe per-user state and start fresh, remove the named volume:
`docker volume rm squarebox-home`.

> **Tip:** Use `sqrbx-update` from inside the container to update tools without
> rebuilding. Only use `sqrbx-rebuild` when the base image itself needs to
Expand All @@ -329,7 +336,7 @@ First-run selections add to that:
| micro / edit | ~12 / ~7 MB |
| fresh / nvim | ~10 / ~45 MB |
| Node.js | ~90 MB |
| Python (uv) | ~35 MB |
| Python | ~50 MB |
| Go | ~500 MB |
| .NET | ~800 MB |

Expand All @@ -342,16 +349,17 @@ Security
Base image tools are pinned to specific versions and verified against SHA256
checksums when the Docker image is built, so `docker build` is reproducible.

Optional tools selected during first-run setup (editors, TUIs, OpenCode, nvm,
Go, zellij) install the latest upstream release at the time you run setup. The
Optional tools selected during first-run setup (editors, TUIs, OpenCode,
zellij) install the latest upstream release at the time you run setup. The
trust model is the same as running each tool's installer yourself: HTTPS
downloads from the project's official GitHub release (or upstream server). You
get new features without waiting for a squarebox release, at the cost of
build-time pinning for that tier.

Third-party install scripts (Claude Code, uv, .NET) delegate to the vendor
installer. npm-based AI tools (Copilot CLI, Gemini CLI, Codex CLI) use npm's
built-in integrity verification.
SDKs (Node, Python, Go, .NET, Rust) are installed by [mise](https://github.com/jdx/mise),
which is itself a Dockerfile-tier pinned binary. mise downloads each SDK
toolchain from its upstream over HTTPS using its own integrity checks. npm-based
AI tools (Copilot CLI, Gemini CLI, Codex CLI) use npm's built-in integrity verification.

For the full trust model (what `install.sh` does on your machine, how each
layer is verified, and how to inspect the script before running it) see
Expand All @@ -378,8 +386,9 @@ Uninstall
sqrbx-uninstall

Removes the container, image, and shell integration but **keeps**
`~/squarebox` (including `workspace/`) so your code is safe by default.
Pass `--purge` to also remove `~/squarebox`:
`~/squarebox` (including `workspace/`) and the `squarebox-home` named volume
(shell history, gh auth, mise toolchains) so your code and per-user state are
safe by default. Pass `--purge` to also remove both:

sqrbx-uninstall --purge

Expand Down
Loading
Loading