Clicking a link in the terminal opens exactly one tab again, on any terminal. The Docker VM size now matches the slider you set (a 24 GB VM no longer reads as "23 GB").
A polish release, no migration. Both fixes came from live use: a link that opened twice and a tuned-VM line that under-reported the configured memory.
Checks that your Docker VM has enough swap, not just enough memory. Stops a phantom "config changed" recreate after you resize the VM or upgrade the CLI.
A polish release, no migration. The headline fix is a recreate prompt that fired on a box you never touched. The swap check rounds out the on-start Docker tuning advice.
Terminal links open exactly once again. An undersized Docker VM is flagged on every start until you fix it. A well-sized one now gets a one-line confirmation instead of silence.
A polish release, no migration. The headline fix is a recurring double-open on terminal links under concurrent sessions. The on-start Docker memory check is now clearer, harder to miss and honest about what it can promise.
Fixes the on-start Docker memory advice that went missing under load on real Macs: the "give Docker more memory" steps now always show, the what's-new note keeps its blank line and the overload notice is honest about a machine that can't grow its VM.
A follow-up to v0.16.1 from a real-Mac report, no migration. All three fixes are in the on-start startup block.
A follow-up to v0.16.0: macOS logins now carry into boxes, out-of-memory crashes are explained with a fix, the Docker memory advice is sized to your actual machine and the outdated-image prompt downloads instead of rebuilding.
All improvements and fixes on top of v0.16.0, no migration. A box and a cleat running in another worktree of the same project are treated as the same thing throughout: one session, one memory ceiling, sharing the one Docker VM.
Native Apple Silicon images, right-sized per-box memory plus optional CPU limits, automatic disk GC and an end to frozen terminals, zombie wedges and duplicate browser tabs.
Everything in this release comes from one live performance investigation: four boxes froze at once, the terminal filled with escape garbage, Docker Desktop showed AMD64 badges on an Apple Silicon Mac and 121 GB of stale images had piled up. Each symptom is fixed at its root cause. Existing boxes get a one-time recreate offer on start. Project files and ~/.claude state survive recreation.
Three real-world fixes: an ssh box now survives a Mac reboot instead of failing to start, cleat upgrade-claude no longer dies with a permission error and the startup output reads as one clean block.
All bug fixes, no new commands, no migration. Pick them up by rebuilding the image (cleat rebuild, or accept the on-start "image is outdated" prompt) so the new entrypoint takes effect.
Cleaner, quieter startup plus a config-drift fix: upgrading Cleat no longer triggers a false "Config changed" prompt, browser links open one tab instead of one per past session and the on-start notices are plain text.
This release is all polish on the start path: the drift check, the update cadence, the release note and the notice styling. No new commands and existing projects upgrade with no migration.
Boxes - multiple named, least-privilege sandboxes per project over the same live files - plus runtime hardening for long-lived containers, the node:24 base image and a single-inspect cleat ps / cleat status.
Run a locked-down dev box beside a cloud-capable az box on the same /workspace, each with its own capabilities, writable layer and Claude session. The default box is byte-identical to the pre-boxes container, so existing projects upgrade with zero migration.
Fixes a startup freeze and a recurring clipboard-daemon permission error that surfaced after upgrading to v0.13.0 on hosts whose UID differs from the image (every macOS user).
Both trace to a freshly recreated container: Claude Code's own launch-time self-updater could hang the TUI and a session could start before the container finished remapping its user - leaving clipboard files owned by the wrong UID.
The bundled Claude Code stays current and per-container state stays put - adds cleat upgrade-claude and an on-start update prompt, fixes native claude update, makes ad-hoc installs survive restarts and removes the cloud CLI caps in favor of host install + the env cap.
Claude Code is no longer frozen for the life of an image: you can bump it in place and Cleat offers to do it for you when a newer build ships. Anything you install inside a container - and its login - now survives cleat restarts instead of silently vanishing. Capabilities slim to two categories (mount / sandbox).
Fixes a long-standing cleat start failure mode - when /tmp rotated individual overlay files but kept the parent dir, the existing container would fail to start with an opaque OCI runtime "not a directory" error instead of cleanly recreating.
User declined the drift recreate prompt, then cleat start aborted with error mounting "/host_mnt/private/tmp/cleat-settings-<cname>/project-settings.local.json" ... not a directory: Are you trying to mount a directory onto a file (or vice-versa)?. Docker auto-creates a missing bind source as a directory, which can't mount onto a file destination inside the container. The pre-fix stale-mount detection only checked dir existence, so this partial-rotation state slipped past the gate and into docker start.
Fixes a v0.12.1 papercut - the new drift recreate prompt rendered as garbled \033[1m...\033[0m literals instead of the intended bold container name. Also fixes a CI-only flake in _hook_bridge_cleanup that was masking real failures under ./test.sh.
The prompt was shipped using echo -n, which prints backslash escapes verbatim. ${BOLD} and ${RESET} are ANSI escape strings that need echo -e to be interpreted. Users hitting the prompt saw Recreate \033[1mcleat-foo\033[0m now? [Y/n] instead of the intended bold container name.
Drift detection now prompts to recreate the container interactively instead of just printing a notice - closes the most common UX gap users hit after cleat config --enable <cap> followed by cleat.
The fingerprint-based drift detection landed in v0.3.0 already covered cap and env-key changes, but the response was a static "Run: cleat rm && cleat" notice. Users who enabled hooks (or any other cap) on an existing container kept the old mount set and silently saw nothing change - hooks never fired, env vars were missing, etc. Now cleat, cleat resume and cleat claude ask "Recreate <cname> now? [Y/n]" before any docker operation. Sessions persist on the host (~/.claude/projects/<key>/) and survive the rebuild, so accepting is safe by default.
aws and gcloud caps round out cloud CLI coverage and the post-launch caps display now groups capabilities by behavioral category - same UI in the CLI and on the landing page.
az introduced the lazy-install framework in v0.11.0. aws and gcloud reuse it. The summary block previously rendered active caps as a single inline row, which scaled poorly past four or five names. The new categorized renderer breaks them into mount / cloud / sandbox lines with consistent colour coding so the categorization itself teaches users what each cap actually does.
az capability and a reusable lazy-install framework - opt-in tools too large to ship in the base image now install inside the container on first activation, with auth dirs persisted on the host.
The gh and docker caps already pre-install their CLIs in every image. That doesn't scale to cloud-vendor tooling: azure-cli is ~250 MB, awscli ~80 MB, google-cloud-cli ~200 MB. Pre-installing all of them would inflate the image for every user. The new lazy-install framework keeps the base image lean and pushes the cost to users who actually opt in. az is the first cap to use it. aws and gcloud are queued to follow the same pattern.
First-run no longer rebuilds locally when a transient pull error hides an already-cached prebuilt image.
_do_pull always issued a network pull against GHCR even when the version-tagged prebuilt image was already on disk. A transient registry, network, or auth error there flipped the image into "unavailable" and triggered a 2-5 min local rebuild - even though the prebuilt image was sitting in the local image store waiting to be reused.
Host Docker daemon access + workspace trust - test dockerized apps from inside the sandbox, without letting untrusted .cleat files silently escalate capabilities.
Two interlocking features. The docker capability mounts your host's Docker socket so docker compose up, docker compose exec and docker build all work against your real daemon from inside Cleat - sibling containers, zero overhead, no DinD. Workspace trust then hardens every capability against supply-chain attacks by gating project-level .cleat files through a per-project approval prompt, so cloning a random repo can no longer silently grant sandbox-escaping Docker access.
First-run now pulls the prebuilt image from GHCR instead of building locally, plus live pull progress and terminal-output polish.
Fresh installs were always supposed to get the ~30s GHCR pull before falling back to a local build, but cmd_run's missing-image branch called the build function directly, skipping the pull entirely. Every clean install was paying the 2-5 min build cost even though a matching prebuilt image was waiting. The pull tag is also version-matched to the installed CLI now and the pull UX shows live layer progress instead of a silent spinner.
macOS hardening - full bash 3.2 compatibility, 538 tests green on both platforms.
Config drift detection, the config command and all smoke tests were broken on macOS due to GNU-only commands (md5sum, timeout), bash 3.2 empty-array crashes and BSD sed incompatibilities. Every issue is fixed and 9 new tests cover the pull-fallback logic, portable hashing and update behavior.
GitHub CLI capability + faster, lighter Docker image.
New gh capability gives the container access to your GitHub CLI auth - gh auth login inside any container writes tokens back to the host, so you authenticate once and it persists across rm, nuke and rebuild. The Docker image switches to node:20-bookworm-slim, drops vim and build-essential and adds pre-built image pull support for faster first starts.
Fix arrow-up history leaking across projects.
The v0.8.0 per-project session overlay isolated projects/-workspace/ but missed ~/.claude/history.jsonl - the global input history file shared via the base ~/.claude mount. Arrow-up in Claude showed commands from other projects. Now history.jsonl is overlaid per-project alongside sessions.
Per-project session isolation - each project gets its own Claude history.
Previously, all containers shared a single ~/.claude directory. cleat resume for project A showed Claude's conversation history from project B. Now each container mounts a per-project session directory so sessions, tasks and project memory are isolated. Auth and global settings remain shared.
511 tests. Zero regressions ever again.
Three independent test layers - regression registry, real-binary smoke tests and a hardened Docker stub - now catch every class of bug that previously shipped undetected. The test suite grew from 383 to 511 tests, all pre-existing failures were fixed and every regression test is mutation-verified to prove it catches its target bug.
cleat login actually works - OAuth callback proxy fixed for IPv6, stdin EOF and busy ports.
The browser bridge's OAuth callback proxy had three latent bugs that made cleat login fail silently in most real-world setups. Authentication completed inside the container, but the browser either hung or showed a spurious "callback forwarding failed" page. All three root causes are now fixed with diagnostic logging so future regressions are visible.
Environment variables work everywhere - shell, login and exec all respect .cleat.env.
Previously, env vars from .cleat.env were only passed at container creation time (docker run). Sessions entered via cleat shell, cleat login, or resumed containers didn't see them. Now all entry points resolve env vars at exec time, so changes to .cleat.env take effect immediately without recreating the container.
Startup diagnostics - see why containers fail, fix them in one keystroke.
After a reboot or Docker restart, stale containers often refuse to start. Previously you'd see "Container failed to start" with no explanation. Now the CLI shows Docker's actual error message and offers to remove and recreate the container automatically.
Browser bridge fix - URLs open reliably again.
Interactive config, polished UI, battle-tested hooks.
TUI capability picker with keyboard navigation. Hooks and browser bridge hardened against stale session data. Notice boxes render cleanly at any width.
Hooks just work - no container recreation needed.
Adding, changing, or removing hooks in your project or global settings takes effect immediately on resume or claude attach. No more cleat rm required.
Simplified hooks - your hooks, running on your host.
Hooks capability redesigned: no custom loggers or injected settings. When enabled, your existing Claude Code hooks from all three settings locations run on the host via the bridge watcher.
Hooks, browser bridge and host connectivity.
Claude Code hooks work transparently - host-defined hooks run on the host, container events are logged to JSONL. Browser URLs from inside the container open on the host with OAuth callbacks proxied back. host.docker.internal is always available.
Unified terminal design system with spinners and clean output.
No Docker noise. Concise status lines with color, braille spinners and suppressed boilerplate.
Opt-in capabilities for git, SSH and environment variables.
Extend what the container can access from the host. All disabled by default - the baseline sandbox is unchanged.
BATS test suite with 121 behavioral tests.
Docker sandbox for AI coding agents. One command. Your host stays untouched.