agent-dev-env 0.1.0-canary.2.fbbd044

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -0
  3. package/dist/assets/bridge/bridge.js +202 -0
  4. package/dist/assets/guest/guest-agent-mac.js +586 -0
  5. package/dist/assets/guest/guest-agent-ubuntu.js +481 -0
  6. package/dist/assets/guest/guest-agent-windows.js +466 -0
  7. package/dist/assets/images/mac/CHANGELOG.md +265 -0
  8. package/dist/assets/images/mac/README.md +63 -0
  9. package/dist/assets/images/mac/sandbox.pkr.hcl +468 -0
  10. package/dist/assets/images/mac/vars/sandbox-macos-tahoe.pkrvars.hcl +39 -0
  11. package/dist/assets/images/ubuntu-arm64-vmware/CHANGELOG.md +239 -0
  12. package/dist/assets/images/ubuntu-arm64-vmware/README.md +177 -0
  13. package/dist/assets/images/ubuntu-arm64-vmware/autoinstall/meta-data +2 -0
  14. package/dist/assets/images/ubuntu-arm64-vmware/autoinstall/user-data +34 -0
  15. package/dist/assets/images/ubuntu-arm64-vmware/sandbox.pkr.hcl +776 -0
  16. package/dist/assets/images/ubuntu-arm64-vmware/vars/sandbox-ubuntu-24-04-arm64-vmware.pkrvars.hcl +71 -0
  17. package/dist/assets/images/windows-arm64-qemu/CHANGELOG.md +209 -0
  18. package/dist/assets/images/windows-arm64-qemu/README.md +142 -0
  19. package/dist/assets/images/windows-arm64-qemu/autounattend.xml +325 -0
  20. package/dist/assets/images/windows-arm64-qemu/qemu-with-tpm.sh +170 -0
  21. package/dist/assets/images/windows-arm64-qemu/sandbox.pkr.hcl +1012 -0
  22. package/dist/assets/images/windows-arm64-qemu/vars/sandbox-windows-11-arm64-qemu.pkrvars.hcl +83 -0
  23. package/dist/assets/images/windows-arm64-vmware/CHANGELOG.md +270 -0
  24. package/dist/assets/images/windows-arm64-vmware/README.md +171 -0
  25. package/dist/assets/images/windows-arm64-vmware/autounattend.xml +311 -0
  26. package/dist/assets/images/windows-arm64-vmware/sandbox.pkr.hcl +1036 -0
  27. package/dist/assets/images/windows-arm64-vmware/vars/sandbox-windows-11-arm64-vmware.pkrvars.hcl +83 -0
  28. package/dist/assets/rules/agent-rules-linux.md +68 -0
  29. package/dist/assets/rules/agent-rules.md +71 -0
  30. package/dist/assets/watchdog/watch-build-ocr.swift +40 -0
  31. package/dist/assets/watchdog/watch-build.py +275 -0
  32. package/dist/cli.js +52 -0
  33. package/dist/commands/delete.js +179 -0
  34. package/dist/commands/doctor.js +165 -0
  35. package/dist/commands/list.js +38 -0
  36. package/dist/commands/not-yet.js +15 -0
  37. package/dist/commands/register.js +150 -0
  38. package/dist/commands/run.js +65 -0
  39. package/dist/commands/status.js +142 -0
  40. package/dist/commands/stop.js +186 -0
  41. package/dist/commands/sync.js +98 -0
  42. package/dist/lib/exec.js +250 -0
  43. package/dist/lib/ghcr.js +82 -0
  44. package/dist/lib/git.js +100 -0
  45. package/dist/lib/logger.js +87 -0
  46. package/dist/lib/network.js +63 -0
  47. package/dist/lib/paths.js +116 -0
  48. package/dist/lib/platform.js +87 -0
  49. package/dist/lib/prompt.js +66 -0
  50. package/dist/lib/qemu.js +373 -0
  51. package/dist/lib/regex.js +9 -0
  52. package/dist/lib/ssh.js +230 -0
  53. package/dist/lib/tart.js +210 -0
  54. package/dist/lib/template.js +35 -0
  55. package/dist/lib/vars.js +99 -0
  56. package/dist/lib/vmrun.js +334 -0
  57. package/dist/lifecycle/build-macos.js +23 -0
  58. package/dist/lifecycle/build-qemu.js +204 -0
  59. package/dist/lifecycle/build-shared.js +355 -0
  60. package/dist/lifecycle/build-ubuntu.js +184 -0
  61. package/dist/lifecycle/build-watchdog.js +146 -0
  62. package/dist/lifecycle/build-windows-vmware.js +112 -0
  63. package/dist/lifecycle/build.js +55 -0
  64. package/dist/lifecycle/catalog.js +165 -0
  65. package/dist/lifecycle/deploy.js +161 -0
  66. package/dist/lifecycle/tag.js +77 -0
  67. package/dist/lifecycle/watch-build.js +64 -0
  68. package/dist/runners/bridges.js +156 -0
  69. package/dist/runners/framework.js +66 -0
  70. package/dist/runners/macos-bridges.js +143 -0
  71. package/dist/runners/macos-guest.js +76 -0
  72. package/dist/runners/macos-rules.js +77 -0
  73. package/dist/runners/macos-summary.js +145 -0
  74. package/dist/runners/macos.js +258 -0
  75. package/dist/runners/openchamber.js +60 -0
  76. package/dist/runners/options.js +56 -0
  77. package/dist/runners/qemu-image.js +183 -0
  78. package/dist/runners/rules.js +49 -0
  79. package/dist/runners/ubuntu-bridges.js +154 -0
  80. package/dist/runners/ubuntu-guest.js +136 -0
  81. package/dist/runners/ubuntu-image.js +26 -0
  82. package/dist/runners/ubuntu-rules.js +86 -0
  83. package/dist/runners/ubuntu-shared.js +65 -0
  84. package/dist/runners/ubuntu-summary.js +141 -0
  85. package/dist/runners/ubuntu.js +117 -0
  86. package/dist/runners/vmware-common.js +158 -0
  87. package/dist/runners/vmware-image.js +242 -0
  88. package/dist/runners/windows-autologon.js +119 -0
  89. package/dist/runners/windows-bridges.js +136 -0
  90. package/dist/runners/windows-guest.js +213 -0
  91. package/dist/runners/windows-image.js +23 -0
  92. package/dist/runners/windows-qemu-summary.js +85 -0
  93. package/dist/runners/windows-qemu.js +189 -0
  94. package/dist/runners/windows-shared.js +68 -0
  95. package/dist/runners/windows-summary.js +104 -0
  96. package/dist/runners/windows.js +96 -0
  97. package/dist/settings/common.js +107 -0
  98. package/dist/settings/macos-copy.js +223 -0
  99. package/dist/settings/macos.js +41 -0
  100. package/dist/settings/ubuntu-copy.js +223 -0
  101. package/dist/settings/ubuntu.js +68 -0
  102. package/package.json +52 -0
@@ -0,0 +1,265 @@
1
+ # Changelog
2
+
3
+ All notable changes to the macOS sandbox images.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ The image version lives in the image's vars file (`image_version`); every
9
+ release bumps it, adds an entry below, and tags the release commit
10
+ `<platform>-v<version>` (e.g. `mac-v1.2.0`). The `[Unreleased]` section on top
11
+ is never removed — changes land there until the next release.
12
+
13
+ ## [Unreleased]
14
+
15
+ ### Added
16
+
17
+ - `agent-dev-env stop` (macos) — stops the sandbox: `tart stop` on the
18
+ working VM plus the host SSH agent / Docker bridge listeners the runner
19
+ leaves up (a bare `tart stop` left the socat listeners running). Honors
20
+ the runner's `SANDBOX_VM` / `SANDBOX_AGENT_PORT` / `SANDBOX_DOCKER_PORT`
21
+ overrides.
22
+ - `agent-dev-env delete` (macos) — deletes the sandbox: stops it first
23
+ (delegating to the stop step), then `tart delete`s the working VM, and
24
+ the pristine image too with `--pristine` (or a `y` at the prompt). Asks
25
+ before deleting unless `--yes`.
26
+ - `agent-dev-env run` (macos) now installs sandbox environment rules into
27
+ the guest's coding agents — opencode's global `AGENTS.md`
28
+ (`~/.config/opencode/AGENTS.md`) and the Copilot CLI's
29
+ `copilot-instructions.md` (`~/.copilot/copilot-instructions.md`) —
30
+ explaining the runtime topology: the Docker remote engine (context
31
+ `host`, published ports reachable at the NAT gateway, volume mounts
32
+ needing host paths), the shared-directory path mapping and the SSH agent
33
+ bridge. The content ships in the repo (`assets/rules/agent-rules.md`);
34
+ the actual work-dir and mount paths are substituted at install time and
35
+ the SSH agent section is included only when the bridge is up. The runner
36
+ asks before installing or updating the rules, and files the user
37
+ modified are replaced only after a confirmation that defaults to no.
38
+
39
+ ### Changed
40
+
41
+ - `agent-dev-env run` (macos) — the summary's stop hints now point at
42
+ `agent-dev-env stop` instead of a bare `tart stop` and a hand-written
43
+ `lsof | xargs kill` for the bridge listeners.
44
+
45
+ ### Fixed
46
+
47
+ - `agent-dev-env run` (macos) — the SSH agent and Docker bridges no
48
+ longer skip their setup when `tart ip` fails right after boot. Both
49
+ bridge setups derived the host gateway from a single `tart ip` call,
50
+ which can fail before the VM's IP is assigned; they now go through a
51
+ shared helper that retries the IP fetch (up to 5 attempts, 2 s apart)
52
+ before giving up.
53
+
54
+ ## [mac-v1.6.0] - 2026-08-20
55
+
56
+ ### Added
57
+
58
+ - OpenCodeReview — the AI-powered code review CLI
59
+ (https://github.com/alibaba/open-code-review), installed globally via npm
60
+ (`@alibaba-group/open-code-review`, provides the `ocr` command).
61
+
62
+ ### Changed
63
+
64
+ - The user-settings copy now includes the OpenCodeReview config
65
+ (`~/.opencodereview/config.json`), so the guest's `ocr` CLI uses the same
66
+ LLM provider and model as the host. The settings version was bumped so
67
+ existing guests are offered the re-copy once.
68
+ - The `.gitconfig` sanitization in the user-settings copy now rewrites
69
+ paths under the host's home directory to the guest's home directory
70
+ (`/Users/admin`) instead of `~`, and no longer drops `program` values —
71
+ the absolute path works even for values git execs verbatim, so a
72
+ home-relative signing wrapper (e.g. `gpg.ssh.program`) survives the
73
+ copy. The settings version was bumped so existing guests are offered the
74
+ re-copy once.
75
+ - The Docker bridge in `scripts/run-macos-sandbox.sh` now also exports
76
+ `DOCKER_HOST` and `TESTCONTAINERS_HOST_OVERRIDE` in the guest's
77
+ `~/.zprofile`, so container-based test frameworks (testcontainers and
78
+ similar) work in the guest out of the box: the Ryuk reaper and published
79
+ ports are reached on the host engine via the NAT gateway instead of the
80
+ guest's `localhost`. Guests set up before this change get the exports the
81
+ next time the runner runs (each `~/.zprofile` block is guarded by its own
82
+ marker, so the socat block is not duplicated).
83
+
84
+ ## [mac-v1.5.0] - 2026-08-20
85
+
86
+ ### Changed
87
+
88
+ - Windowed runs of `scripts/run-macos-sandbox.sh` now pass Tart's
89
+ `--capture-system-keys` flag by default, so system shortcuts (Cmd+Space,
90
+ Cmd+Tab, ...) go to the guest while the VM window is focused instead of
91
+ being handled by the host. Headless runs are unaffected.
92
+ - The user-settings copy now includes the mcp-compress-router settings
93
+ (`~/Library/Application Support/mcp-compress-router/`): the MCP server
94
+ config (`mcp.json`) with its endpoints and credentials, the stored
95
+ credentials, and the tool-schema cache, so the guest's opencode sessions
96
+ can use the same MCP servers. The settings version was bumped so existing
97
+ guests are offered the re-copy once.
98
+ - The OpenChamber web UI now listens on port 4000 instead of 3000 — 3000 is
99
+ the default Vite dev-server port, so frontend dev servers in the guest no
100
+ longer collide with it. The guest port is now a Packer variable
101
+ (`openchamber_port` in the vars file), and the runner's
102
+ `SANDBOX_OPENCHAMBER_PORT` default was bumped to match.
103
+
104
+ ## [mac-v1.4.0] - 2026-08-19
105
+
106
+ ### Added
107
+
108
+ - Sublime Text (current stable build, Homebrew cask `sublime-text`) with the
109
+ `subl` CLI; the quarantine attribute is stripped so it launches without
110
+ Gatekeeper prompts.
111
+ - The OpenChamber native macOS desktop app
112
+ (`/Applications/OpenChamber.app`, Homebrew cask `openchamber`), installed
113
+ alongside the web UI for working inside the guest desktop; the quarantine
114
+ attribute is stripped so it launches without Gatekeeper prompts. The app
115
+ bundles its own OpenCode CLI and manages its own server by default —
116
+ `docs/macos.md` explains how to pair it with the web UI service on port
117
+ 3000 so both share sessions.
118
+ - New `scripts/sync-macos-sandbox.sh`: copies the host's user settings into
119
+ the guest on demand (no VM restart needed), updates the versioned marker
120
+ so the runner won't re-offer the copy, and restarts OpenChamber. Requires
121
+ a running VM; pass `--yes` to skip the confirmation prompt.
122
+ - Docker CLI (`docker` formula) with the `docker compose` and `docker buildx`
123
+ plugins (Homebrew `docker-compose`/`docker-buildx`, discovered via
124
+ `cliPluginsExtraDirs` in `~/.docker/config.json`). Client only: the sandbox
125
+ is a macOS VM, and Apple's Virtualization.framework doesn't support nested
126
+ virtualization for macOS guests, so no container engine (Docker Desktop,
127
+ Colima, ...) can run inside it — `docs/macos.md` explains how to point the
128
+ CLI at a remote engine, e.g. the host's Docker Desktop over SSH.
129
+ - `scripts/run-macos-sandbox.sh` now bridges the host's Docker engine into
130
+ the guest, mirroring the SSH agent bridge: it detects an engine socket on
131
+ the host (Docker Desktop, Colima, OrbStack, `/var/run/docker.sock`), serves
132
+ it over a host-side `socat` TCP listener for the current run, persists a
133
+ guest-side `socat` in the guest's `~/.zprofile` that recreates
134
+ `~/.docker/run/docker.sock` on every login, and creates the docker context
135
+ `host` in the guest so `docker`/`docker compose`/`docker buildx` use the
136
+ host engine. `--no-docker` skips the bridge; `SANDBOX_DOCKER_PORT`
137
+ overrides the bridge port (default `4101`).
138
+
139
+ ### Changed
140
+
141
+ - The user-settings copy now sanitizes `.gitconfig` for the guest, where the
142
+ user differs (the image's `admin` vs. the host login): paths under the
143
+ host's home directory are rewritten to `~` (git expands `~` for path-like
144
+ keys and the shell does for `core.sshCommand`), and `program = ~/...`
145
+ values are dropped — git execs program values verbatim, and the
146
+ `gpg.ssh.program` signing wrapper is a host-only workaround; the guest
147
+ signs through the bridged SSH agent instead. The settings version was
148
+ bumped so existing guests are offered the re-copy once.
149
+ - The user-settings copy (runner and the new sync script) now covers the
150
+ whole global opencode config directory: `opencode.json`/`.jsonc`,
151
+ `tui.json`/`.jsonc`, and the `agents/`, `commands/`, `modes/`, `plugins/`,
152
+ `skills/`, `tools/` and `themes/` directories, plus the config dir's
153
+ `package.json`/lockfiles for local plugin dependencies (npm plugins are
154
+ auto-installed by opencode at startup, so `node_modules` stays on the
155
+ host). The settings version was bumped so existing guests are offered the
156
+ re-copy once. The copy logic was extracted into
157
+ `scripts/lib/macos-settings.sh`, shared by `scripts/run-macos-sandbox.sh`
158
+ and `scripts/sync-macos-sandbox.sh`.
159
+ - The user-settings copy now includes the Copilot CLI config and skills
160
+ (`~/.copilot/config.json` and `~/.copilot/skills/`); machine-specific
161
+ `~/.copilot/logs`/`ide` are skipped. Copilot auth is not copied — it lives
162
+ in the macOS Keychain, so the guest signs in once. The settings version
163
+ was bumped so existing guests are offered the re-copy once.
164
+ - The user-settings copy now includes the installed VS Code extensions
165
+ (`~/.vscode/extensions/`), so they don't have to be reinstalled in the
166
+ guest, and the user-authored VS Code config (`settings.json`,
167
+ `keybindings.json` and `snippets/` under
168
+ `~/Library/Application Support/Code/User/`), which carries per-extension
169
+ settings. Extension auth and machine-specific state are not copied —
170
+ keychain-stored tokens (Copilot, GitHub, ...) don't travel with files, so
171
+ those extensions ask to sign in once in the guest, and the `globalStorage`/
172
+ `workspaceStorage` caches stay on the host. The settings version was bumped
173
+ so existing guests are offered the re-copy once.
174
+ - `scripts/run-macos-sandbox.sh` now runs the VM in the background by
175
+ default: `tart run` is nohup'd to
176
+ `~/Library/Logs/agent-dev-env/tart-<vm>.log` and the script exits after
177
+ the summary while the VM keeps running (`tart stop <vm>` to stop it). Pass
178
+ `--foreground` to keep the terminal attached and block until the VM stops,
179
+ as before. When the VM is already running, the script now asks whether to
180
+ restart it instead of silently reusing it.
181
+
182
+ ## [mac-v1.3.0] - 2026-08-19
183
+
184
+ ### Added
185
+
186
+ - `scripts/run-macos-sandbox.sh` now offers to copy the host's user settings
187
+ into the guest — opencode config (`~/.config/opencode/opencode.json` /
188
+ `.jsonc`) and auth (`~/.local/share/opencode/auth.json`), plus
189
+ `~/.ssh/allowed_signers`, `~/.ssh/known_hosts`, `~/.ssh/*.sh` and
190
+ `~/.gitconfig` — once per VM, tracked by a versioned marker inside the
191
+ guest (`~/.config/agent-dev-env/settings-copied`); bumping the settings
192
+ version in the script re-copies when new settings are added. Skip with
193
+ `--no-settings`.
194
+ - The guest's `~/.ssh/config` now pins `IdentityAgent /tmp/ssh-agent.sock`
195
+ for all hosts, so `ssh` works through the bridged host agent even where
196
+ `SSH_AUTH_SOCK` is not exported (`tart exec`, cron, launchd jobs, GUI
197
+ tools). Applied idempotently on every run; guests set up before this patch
198
+ get it too.
199
+
200
+ ### Changed
201
+
202
+ - The template's `disk_size` default is now 160 GB (matching the vars files
203
+ and the built images) — the previous 80 GB default was below the ~140 GB
204
+ Cirrus base image disk, and tart can only grow a disk, never shrink it. No
205
+ effect on released images; only relevant when a vars file omits `disk_size`.
206
+ - `scripts/deploy.sh` pushes in 3 MB chunks (`tart push --chunk-size 3`)
207
+ because GHCR only accepts upload chunks smaller than 4 MB.
208
+
209
+ ## [mac-v1.2.0] - 2026-08-19
210
+
211
+ ### Added
212
+
213
+ - Google Chrome and Mozilla Firefox (latest stable universal macOS builds)
214
+ installed via Homebrew casks; the quarantine attribute is stripped so they
215
+ launch without Gatekeeper prompts — the VM boots straight to the desktop
216
+ and may run headless.
217
+
218
+ ### Changed
219
+
220
+ - The OpenChamber LaunchAgent now runs the exact `opencode` binary the image
221
+ ships: the build resolves `command -v opencode` and pins the absolute path
222
+ via `OPENCODE_BINARY` before `openchamber startup enable` snapshots the
223
+ environment, instead of relying on PATH lookup in the login session.
224
+ Rebuilding the image is required for this to take effect.
225
+ - The sandbox runs with no audio pass-through with the host: builds pass
226
+ `--no-audio` to Tart, and the docs recommend `tart run --no-audio` so the
227
+ guest can't record from the host's microphone or play sound on the host's
228
+ speakers. No image content change — audio sharing is a runtime Tart flag,
229
+ so existing images are unaffected.
230
+
231
+ ## [mac-v1.1.0] - 2026-08-19
232
+
233
+ ### Added
234
+
235
+ - OpenChamber (web UI for OpenCode, https://openchamber.dev) installed via
236
+ `@openchamber/web` and registered as a login service (LaunchAgent) that
237
+ listens on `0.0.0.0:3000`, so the host can open the UI at
238
+ `http://<vm-ip>:3000`. The UI is password-protected
239
+ (`openchamber_ui_password` in the vars file, default `sandbox`); see
240
+ `docs/macos.md` for host access and how to change the password.
241
+
242
+ ## [mac-v1.0.0] - 2026-08-19
243
+
244
+ First versioned release of the `sandbox-macos-tahoe` image (macOS 26 Tahoe +
245
+ Xcode 26.4.1).
246
+
247
+ ### Added
248
+
249
+ - System setup: auto-login as `admin`/`admin`, Remote Login (SSH), Screen
250
+ Sharing (VNC), friendly hostname, Tart Guest Agent check.
251
+ - Homebrew toolchain: `bash`, `git`, `gh`, `jq`, `ripgrep`, `coreutils`,
252
+ `curl`, `wget`, `socat`, `nvm`, `python@3.14`, `ruby`.
253
+ - Node.js 26 installed via nvm (default version, includes npm).
254
+ - Unversioned `python`/`pip` aliases pointing at `python@3.14`.
255
+ - Visual Studio Code (latest stable) with the `code` CLI on PATH.
256
+ - OpenCode (AI coding agent) via the anomalyco Homebrew tap.
257
+
258
+ [unreleased]: https://github.com/ameshkov/agent-dev-env/compare/mac-v1.6.0...HEAD
259
+ [mac-v1.6.0]: https://github.com/ameshkov/agent-dev-env/releases/tag/mac-v1.6.0
260
+ [mac-v1.5.0]: https://github.com/ameshkov/agent-dev-env/releases/tag/mac-v1.5.0
261
+ [mac-v1.4.0]: https://github.com/ameshkov/agent-dev-env/releases/tag/mac-v1.4.0
262
+ [mac-v1.3.0]: https://github.com/ameshkov/agent-dev-env/releases/tag/mac-v1.3.0
263
+ [mac-v1.2.0]: https://github.com/ameshkov/agent-dev-env/releases/tag/mac-v1.2.0
264
+ [mac-v1.1.0]: https://github.com/ameshkov/agent-dev-env/releases/tag/mac-v1.1.0
265
+ [mac-v1.0.0]: https://github.com/ameshkov/agent-dev-env/releases/tag/mac-v1.0.0
@@ -0,0 +1,63 @@
1
+ # macOS Sandbox Images
2
+
3
+ macOS VM images for agent sandboxes, built with [Tart](https://tart.run/) and
4
+ [Packer](https://www.packer.io/).
5
+
6
+ See [docs/macos.md](../../docs/macos.md) for how to pull and run these images,
7
+ and [DEVELOPMENT.md](../../DEVELOPMENT.md) for how to build and publish them.
8
+
9
+ ## Available images
10
+
11
+ Each image is a single macOS version; the image name is fixed per version
12
+ (`sandbox-macos-<macos-version>`) and does not include the Xcode version:
13
+
14
+ | Image | macOS |
15
+ | --- | --- |
16
+ | `sandbox-macos-tahoe` | 26 (Tahoe) |
17
+
18
+ ## Versioning
19
+
20
+ Images are published with semantic version tags (`:1.2.0`, `:latest`). The
21
+ current version lives in the image's vars file (`image_version`); every release
22
+ bumps it, adds a [CHANGELOG.md](CHANGELOG.md) entry, and tags the release
23
+ commit `mac-v<version>` (e.g. `mac-v1.2.0`, created with
24
+ `npx agent-dev-env tag <image>`).
25
+
26
+ ## Building locally
27
+
28
+ Prerequisites: macOS host with Apple Silicon, [Tart](https://tart.run/),
29
+ [Packer](https://www.packer.io/) (`brew install hashicorp/tap/packer`).
30
+ The Tart Packer plugin is installed automatically by `packer init`.
31
+
32
+ ```bash
33
+ # Run from the repository root
34
+
35
+ npx agent-dev-env build <image-name>
36
+
37
+ # Example:
38
+ npx agent-dev-env build sandbox-macos-tahoe
39
+
40
+ # Or build every image:
41
+ npx agent-dev-env build
42
+ ```
43
+
44
+ `agent-dev-env` is the CLI shipped by this repo (see
45
+ [docs/cli.md](../../docs/cli.md)). The first build pulls the ~50 GB base
46
+ image (`ghcr.io/cirruslabs/macos-tahoe-xcode:26.4.1`) and takes a while.
47
+ Note that the builder fails if a VM with the same name already exists —
48
+ remove it first with `tart delete <image-name>`.
49
+
50
+ ## Publishing
51
+
52
+ Images are published to GHCR under
53
+ `ghcr.io/<owner>/<image>:<version>` (the package name equals the image
54
+ name, e.g. `sandbox-macos-tahoe`) — build locally with
55
+ `npx agent-dev-env build`, then push with `npx agent-dev-env deploy`. The
56
+ version tag is the image's `image_version` from its vars file:
57
+
58
+ ```bash
59
+ # One-time: authenticate against GHCR with a token that has `packages:write`
60
+ tart login ghcr.io
61
+
62
+ npx agent-dev-env deploy sandbox-macos-tahoe
63
+ ```