@madarco/agentbox 0.5.0 → 0.7.0

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 (62) hide show
  1. package/dist/_cloud-attach-DMVH6GWO.js +12 -0
  2. package/dist/chunk-7KOEFGN2.js +1162 -0
  3. package/dist/chunk-7KOEFGN2.js.map +1 -0
  4. package/dist/chunk-I24B6AXR.js +600 -0
  5. package/dist/chunk-I24B6AXR.js.map +1 -0
  6. package/dist/chunk-NAVL4R34.js +7546 -0
  7. package/dist/chunk-NAVL4R34.js.map +1 -0
  8. package/dist/chunk-NW5NYTQM.js +1366 -0
  9. package/dist/chunk-NW5NYTQM.js.map +1 -0
  10. package/dist/chunk-UK72UQ5U.js +237 -0
  11. package/dist/chunk-UK72UQ5U.js.map +1 -0
  12. package/dist/chunk-V5KZGB5V.js +722 -0
  13. package/dist/chunk-V5KZGB5V.js.map +1 -0
  14. package/dist/cloud-poller-ZIWSADJB-JXFRJUEM.js +10 -0
  15. package/dist/dist-ETCFRVPA.js +423 -0
  16. package/dist/dist-QZGJIBT5.js +1339 -0
  17. package/dist/dist-QZGJIBT5.js.map +1 -0
  18. package/dist/dist-R67WMLCF.js +183 -0
  19. package/dist/dist-R67WMLCF.js.map +1 -0
  20. package/dist/index.js +4088 -1451
  21. package/dist/index.js.map +1 -1
  22. package/package.json +9 -4
  23. package/runtime/docker/Dockerfile.box +115 -19
  24. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +34 -19
  25. package/runtime/docker/packages/ctl/dist/bin.cjs +10246 -758
  26. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup +13 -3
  27. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-codex-hooks.json +37 -0
  28. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-dockerd-start +87 -7
  29. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-open +28 -0
  30. package/runtime/docker/packages/sandbox-docker/scripts/custom-system-CLAUDE.md +4 -9
  31. package/runtime/hetzner/agentbox-checkpoint-cleanup +52 -0
  32. package/runtime/hetzner/agentbox-codex-hooks.json +37 -0
  33. package/runtime/hetzner/agentbox-dockerd-start +132 -0
  34. package/runtime/hetzner/agentbox-open +28 -0
  35. package/runtime/hetzner/agentbox-setup-skill.md +196 -0
  36. package/runtime/hetzner/agentbox-vnc-start +77 -0
  37. package/runtime/hetzner/claude-managed-settings.json +54 -0
  38. package/runtime/hetzner/ctl.cjs +22350 -0
  39. package/runtime/hetzner/custom-system-CLAUDE.md +27 -0
  40. package/runtime/hetzner/scripts/install-box.sh +365 -0
  41. package/runtime/relay/bin.cjs +9182 -754
  42. package/share/agentbox-setup/SKILL.md +34 -19
  43. package/dist/chunk-6VTAPD4H.js +0 -507
  44. package/dist/chunk-6VTAPD4H.js.map +0 -1
  45. package/dist/chunk-7J5AJLWG.js +0 -238
  46. package/dist/chunk-7J5AJLWG.js.map +0 -1
  47. package/dist/chunk-FJNIFTWK.js +0 -523
  48. package/dist/chunk-FJNIFTWK.js.map +0 -1
  49. package/dist/chunk-HPZMD5DE.js +0 -106
  50. package/dist/chunk-HPZMD5DE.js.map +0 -1
  51. package/dist/chunk-PXUBE5KS.js +0 -2346
  52. package/dist/chunk-PXUBE5KS.js.map +0 -1
  53. package/dist/chunk-RFC5F5HR.js +0 -1709
  54. package/dist/chunk-RFC5F5HR.js.map +0 -1
  55. package/dist/create-AHZ3GVEZ-TGEDL7UX.js +0 -15
  56. package/dist/lifecycle-LFOL6YFM-TCHDX3J5.js +0 -38
  57. package/dist/state-KD7M46ZP-KHFTHFUS.js +0 -26
  58. package/dist/stats-Z4BVJODD-HEC4TMUZ.js +0 -19
  59. package/dist/stats-Z4BVJODD-HEC4TMUZ.js.map +0 -1
  60. /package/dist/{create-AHZ3GVEZ-TGEDL7UX.js.map → _cloud-attach-DMVH6GWO.js.map} +0 -0
  61. /package/dist/{lifecycle-LFOL6YFM-TCHDX3J5.js.map → cloud-poller-ZIWSADJB-JXFRJUEM.js.map} +0 -0
  62. /package/dist/{state-KD7M46ZP-KHFTHFUS.js.map → dist-ETCFRVPA.js.map} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@madarco/agentbox",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Launch Claude Code, Codex, and other coding agents in isolated sandboxes",
5
5
  "license": "MIT",
6
6
  "author": "Marco D'Alia",
@@ -41,6 +41,7 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "@clack/prompts": "^0.9.0",
44
+ "@daytonaio/sdk": "^0.179.0",
44
45
  "@xterm/headless": "^5.5.0",
45
46
  "commander": "^12.1.0",
46
47
  "execa": "^9.5.2",
@@ -56,10 +57,14 @@
56
57
  "typescript": "^5.7.2",
57
58
  "vitest": "^2.1.8",
58
59
  "@agentbox/core": "0.0.0",
59
- "@agentbox/relay": "0.0.0",
60
- "@agentbox/ctl": "0.0.0",
61
60
  "@agentbox/config": "0.0.0",
62
- "@agentbox/sandbox-docker": "0.0.0"
61
+ "@agentbox/ctl": "0.0.0",
62
+ "@agentbox/relay": "0.0.0",
63
+ "@agentbox/sandbox-cloud": "0.0.0",
64
+ "@agentbox/sandbox-core": "0.0.0",
65
+ "@agentbox/sandbox-daytona": "0.0.0",
66
+ "@agentbox/sandbox-docker": "0.0.0",
67
+ "@agentbox/sandbox-hetzner": "0.0.0"
63
68
  },
64
69
  "scripts": {
65
70
  "build": "tsup",
@@ -5,9 +5,9 @@
5
5
  # Silicon hosts). /workspace is a plain dir in the image's writable layer:
6
6
  # `agentbox create` populates it via in-container `git worktree add` (or a
7
7
  # tar pipe for the no-git case). The old FUSE overlay over /host-src+/upper
8
- # is gone — but fuse3 + fuse-overlayfs stay because the in-box dockerd uses
9
- # fuse-overlayfs as its storage driver. Plus the "universal-ish" set of
10
- # language runtimes (Node.js 22 from NodeSource, Python 3 from apt). Heavier
8
+ # is gone — but fuse3 + fuse-overlayfs stay as the in-box dockerd's fallback
9
+ # storage driver (it prefers the kernel-native overlay2). Plus the "universal-ish" set of
10
+ # language runtimes (Node.js 24 from NodeSource, Python 3 from apt). Heavier
11
11
  # tooling (Go, Java, Ruby, .NET, more browser tooling, vscode-server) goes in
12
12
  # a later iteration.
13
13
  #
@@ -57,7 +57,7 @@ ENV COLORTERM=truecolor \
57
57
  RUN apt-get update \
58
58
  && apt-get install -y --no-install-recommends \
59
59
  curl ca-certificates gnupg \
60
- && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
60
+ && curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
61
61
  && apt-get install -y --no-install-recommends \
62
62
  fuse3 \
63
63
  fuse-overlayfs \
@@ -87,7 +87,7 @@ RUN setcap cap_net_bind_service=+ep "$(readlink -f "$(command -v node)")"
87
87
  # Enable corepack (pnpm/yarn shims) at build time as root. Doing this here
88
88
  # rather than in the wizard's install task avoids two failures the runtime
89
89
  # `corepack enable` (run as non-root `vscode`) hits: it can't write shims into
90
- # the root-owned NodeSource bin dir (/usr/bin), and node 22's bundled corepack
90
+ # the root-owned NodeSource bin dir (/usr/bin), and node 24's bundled corepack
91
91
  # resolves its dist path relative to the symlink dirname, so a
92
92
  # ~/.local/bin/pnpm symlink looks for ~/.local/dist/pnpm.js and breaks.
93
93
  # `corepack@latest` fixes the symlink resolution; baking the shims into
@@ -97,6 +97,13 @@ RUN setcap cap_net_bind_service=+ep "$(readlink -f "$(command -v node)")"
97
97
  RUN npm install -g corepack@latest \
98
98
  && corepack enable pnpm yarn
99
99
 
100
+ # Pre-create the corepack download cache owned by `vscode`. Without this,
101
+ # the first corepack-driven install (e.g. the setup wizard's verification
102
+ # step) hits ENOENT on /home/vscode/.cache/node/corepack/v1 because nothing
103
+ # else creates ~/.cache for the runtime user.
104
+ RUN mkdir -p /home/vscode/.cache/node/corepack \
105
+ && chown -R vscode:vscode /home/vscode/.cache
106
+
100
107
  # Host repos are bind-mounted in at their identical absolute path (worktree
101
108
  # pointer files contain absolute paths to <main>/.git/worktrees/<name>, so both
102
109
  # sides have to resolve the same path), and the host owns those `.git/` dirs.
@@ -105,14 +112,15 @@ RUN npm install -g corepack@latest \
105
112
  # bind-mount of ~/.gitconfig from the host.
106
113
  RUN git config --system --add safe.directory '*'
107
114
 
108
- # Docker-in-Docker. dockerd inside the box (storage-driver=fuse-overlayfs, set
109
- # in /etc/docker/daemon.json) lets the agent run `docker build`/`docker run`
110
- # in its own namespace without exposing the host daemon. fuse-overlayfs is
111
- # required because the kernel `overlay` driver isn't usable from an
112
- # unprivileged container fuse3 + fuse-overlayfs are installed above
113
- # specifically for this (the outer /workspace overlay is gone, but the inner
114
- # dockerd still needs them). iptables is needed
115
- # for inner-container bridge networking. Adding `vscode` to the `docker` group
115
+ # Docker-in-Docker. dockerd inside the box lets the agent run
116
+ # `docker build`/`docker run` in its own namespace without exposing the host
117
+ # daemon. The storage driver is NOT pinned here: agentbox-dockerd-start picks
118
+ # it at runtime — the kernel-native overlay2 when a probe proves it works on
119
+ # the data-root filesystem, else the fuse-overlayfs fallback (fuse3 +
120
+ # fuse-overlayfs are installed above for that fallback). The baked daemon.json
121
+ # only carries `iptables: true`; the script rewrites it with the resolved
122
+ # `storage-driver` before launching dockerd. iptables is needed for
123
+ # inner-container bridge networking. Adding `vscode` to the `docker` group
116
124
  # lets the agent invoke `docker` without sudo once dockerd creates the socket
117
125
  # at /var/run/docker.sock at runtime. The matching launch script is COPY'd in
118
126
  # below; the daemon is started by the host via `docker exec -d --user root`
@@ -123,7 +131,7 @@ RUN apt-get update \
123
131
  iptables \
124
132
  && rm -rf /var/lib/apt/lists/* \
125
133
  && mkdir -p /etc/docker \
126
- && printf '%s\n' '{ "storage-driver": "fuse-overlayfs", "iptables": true }' > /etc/docker/daemon.json \
134
+ && printf '%s\n' '{ "iptables": true }' > /etc/docker/daemon.json \
127
135
  && usermod -aG docker vscode
128
136
 
129
137
  # agentbox-ctl: the in-container supervisor + CLI. Build context is the
@@ -160,6 +168,38 @@ RUN mkdir -p /home/vscode/.claude \
160
168
  && ln -s /home/vscode/.claude/_claude.json /home/vscode/.claude.json \
161
169
  && chown -h vscode:vscode /home/vscode/.claude.json
162
170
 
171
+ # Cloud-provider credential pivot: ~/.agentbox-creds/<agent>/ is where the
172
+ # per-org `agentbox-credentials` Daytona volume gets mounted at runtime (three
173
+ # subpath mounts: claude/, codex/, opencode/). Three symlinks route the
174
+ # agent-expected credential paths through to it so the in-box agent reads
175
+ # tokens from the volume while the surrounding config sits on the snapshot-
176
+ # baked sandbox FS.
177
+ #
178
+ # These symlinks are dangling at build time — their targets only resolve once
179
+ # the volume is mounted. That's fine: ln succeeds, and the kernel resolves
180
+ # symlinks lazily on open().
181
+ #
182
+ # The Docker provider is unaffected: its named `agentbox-{claude,codex,
183
+ # opencode}-config` volumes mount *over* /home/vscode/.claude etc., obscuring
184
+ # the symlinks; the volume content includes the credential files directly.
185
+ RUN mkdir -p /home/vscode/.agentbox-creds/claude \
186
+ /home/vscode/.agentbox-creds/codex \
187
+ /home/vscode/.agentbox-creds/opencode \
188
+ /home/vscode/.codex \
189
+ /home/vscode/.local/share/opencode \
190
+ && ln -s /home/vscode/.agentbox-creds/claude/.credentials.json \
191
+ /home/vscode/.claude/.credentials.json \
192
+ && ln -s /home/vscode/.agentbox-creds/codex/auth.json \
193
+ /home/vscode/.codex/auth.json \
194
+ && ln -s /home/vscode/.agentbox-creds/opencode/auth.json \
195
+ /home/vscode/.local/share/opencode/auth.json \
196
+ && chown -R vscode:vscode /home/vscode/.agentbox-creds \
197
+ /home/vscode/.codex \
198
+ /home/vscode/.local \
199
+ && chown -h vscode:vscode /home/vscode/.claude/.credentials.json \
200
+ /home/vscode/.codex/auth.json \
201
+ /home/vscode/.local/share/opencode/auth.json
202
+
163
203
  # Prepare /home/vscode/.vscode-server and /home/vscode/.cursor-server (+ their
164
204
  # extensions subdirs) so the named volumes mounted at runtime — per-box
165
205
  # `agentbox-{vscode,cursor}-server-<id>` over the server dirs, then shared
@@ -183,6 +223,29 @@ USER vscode
183
223
  RUN curl -fsSL https://claude.ai/install.sh | bash -s stable
184
224
  USER root
185
225
 
226
+ # OpenAI Codex CLI. The @openai/codex npm package ships platform-native
227
+ # prebuilds for linux arm64/amd64, so a plain global install is enough.
228
+ # Parallel to the Claude Code install above: `agentbox codex` launches it in a
229
+ # tmux session and the box mounts a synced `agentbox-codex-config` volume at
230
+ # ~/.codex for auth/config (see packages/sandbox-docker/src/codex.ts).
231
+ #
232
+ # `bubblewrap` (bwrap) is Codex's command-sandbox backend; without it on PATH
233
+ # Codex falls back to a bundled copy and prints a warning on every run. It
234
+ # works nested because the agentbox container already runs with --cap-add
235
+ # SYS_ADMIN + apparmor:unconfined.
236
+ RUN apt-get update \
237
+ && apt-get install -y --no-install-recommends bubblewrap \
238
+ && rm -rf /var/lib/apt/lists/* \
239
+ && npm install -g @openai/codex
240
+
241
+ # OpenCode CLI (sst/opencode) — the multi-provider terminal coding agent.
242
+ # Parallel to the Claude/Codex installs: `agentbox opencode` launches it in a
243
+ # tmux session and the box mounts a synced `agentbox-opencode-config` volume
244
+ # (see packages/sandbox-docker/src/opencode.ts). OpenCode splits its state
245
+ # across ~/.config/opencode (config) and ~/.local/share/opencode (data + auth);
246
+ # the volume holds both, with the config dir relocated via OPENCODE_CONFIG_DIR.
247
+ RUN npm install -g opencode-ai
248
+
186
249
  # Browser support for in-box agents: Vercel's agent-browser drives Chrome via
187
250
  # CDP. Two things have to happen here:
188
251
  #
@@ -216,15 +279,26 @@ RUN apt-get update \
216
279
 
217
280
  RUN npm install -g agent-browser playwright
218
281
 
282
+ # Portless CLI (https://portless.sh). Only the client — the box never runs the
283
+ # proxy; that's a host process. With `portless.enabled`, createBox bind-mounts
284
+ # the host's Portless state dir into the box and sets PORTLESS_STATE_DIR, so
285
+ # the in-box `portless list`/`get` share the host's route registry (discovery).
286
+ # Requires Node 24+ — hence the setup_24.x bump above.
287
+ RUN npm install -g portless
288
+
219
289
  # Download Chromium as `vscode` so the ms-playwright cache lands in vscode's
220
290
  # home (the user agent-browser runs as). The downloaded binary lives at
221
- # `chromium-XXXX/chrome-linux/chrome`, where XXXX is a Playwright-internal
222
- # revision number that changes between releases — we resolve it once here and
223
- # write the result to a stable symlink so AGENT_BROWSER_EXECUTABLE_PATH can
224
- # point at something predictable.
291
+ # `chromium-XXXX/chrome-linux*/chrome`, where XXXX is a Playwright-internal
292
+ # revision number that changes between releases — and the inner dir is
293
+ # `chrome-linux` for old releases and `chrome-linux64` (or `chrome-linux/arm64`)
294
+ # for current Chrome-for-Testing builds. Glob both. We resolve once and write
295
+ # a stable symlink so AGENT_BROWSER_EXECUTABLE_PATH can point at something
296
+ # predictable.
225
297
  USER vscode
226
298
  RUN playwright install chromium \
227
- && ln -sf "$(ls /home/vscode/.cache/ms-playwright/chromium-*/chrome-linux/chrome | sort | tail -1)" /tmp/chromium-link \
299
+ && CHROME_BIN="$(ls /home/vscode/.cache/ms-playwright/chromium-*/chrome-linux*/chrome 2>/dev/null | sort | tail -1)" \
300
+ && test -n "$CHROME_BIN" \
301
+ && ln -sf "$CHROME_BIN" /tmp/chromium-link \
228
302
  && test -x "$(readlink /tmp/chromium-link)"
229
303
  USER root
230
304
  RUN mv /tmp/chromium-link /usr/local/bin/chromium
@@ -284,6 +358,17 @@ RUN chmod +x /usr/local/bin/agentbox-dockerd-start
284
358
  COPY packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup /usr/local/bin/agentbox-checkpoint-cleanup
285
359
  RUN chmod +x /usr/local/bin/agentbox-checkpoint-cleanup
286
360
 
361
+ # In-box link opener. This wrapper routes http(s) URLs to `agentbox-ctl open`,
362
+ # which opens the link in the box's own Chromium (agent-browser) and notifies
363
+ # the relay so the host user can be offered to also open it on the host. It
364
+ # shadows xdg-utils' /usr/bin/xdg-open (the symlink lands earlier in PATH) and
365
+ # is set as $BROWSER so any tool that opens a link — Claude Code's OAuth flow,
366
+ # `gh`, `git web--browse`, python's webbrowser — routes through it.
367
+ COPY packages/sandbox-docker/scripts/agentbox-open /usr/local/bin/agentbox-open
368
+ RUN chmod +x /usr/local/bin/agentbox-open \
369
+ && ln -sf /usr/local/bin/agentbox-open /usr/local/bin/xdg-open
370
+ ENV BROWSER=/usr/local/bin/agentbox-open
371
+
287
372
  # tmux config so Claude's true-color output and OSC 8 hyperlinks survive the
288
373
  # in-container tmux. `terminal-features` is a no-op on tmux < 3.4. Without
289
374
  # this, claude renders without 24-bit color (logo invisible) and hyperlinks
@@ -297,6 +382,10 @@ RUN printf '%s\n' \
297
382
  'set -as terminal-overrides ",*:RGB"' \
298
383
  'set -as terminal-features ",*:hyperlinks"' \
299
384
  'set -as terminal-features ",*:RGB"' \
385
+ 'set -g allow-passthrough on' \
386
+ 'set -g set-clipboard on' \
387
+ 'set -g extended-keys on' \
388
+ 'set -as terminal-features ",*:extkeys"' \
300
389
  'set -g mouse on' \
301
390
  'bind -T copy-mode WheelUpPane send -N2 -X scroll-up' \
302
391
  'bind -T copy-mode WheelDownPane send -N2 -X scroll-down' \
@@ -325,6 +414,13 @@ RUN chmod 0644 /etc/claude-code/CLAUDE.md
325
414
  COPY packages/sandbox-docker/scripts/claude-managed-settings.json /etc/claude-code/managed-settings.json
326
415
  RUN chmod 0644 /etc/claude-code/managed-settings.json
327
416
 
417
+ # Codex activity-reporting hooks. Unlike Claude's managed-settings (an /etc
418
+ # enterprise path), Codex discovers hooks at ~/.codex/hooks.json — so this is
419
+ # staged in the image and seeded into the codex-config volume by
420
+ # seedCodexHooks() at create/start time. See packages/sandbox-docker/src/codex.ts.
421
+ COPY packages/sandbox-docker/scripts/agentbox-codex-hooks.json /usr/local/share/agentbox/codex-hooks.json
422
+ RUN chmod 0644 /usr/local/share/agentbox/codex-hooks.json
423
+
328
424
  # /etc/agentbox/ holds runtime-injected box.env (written by `agentbox create`
329
425
  # via docker exec). Pre-created here so the writable layer starts with the
330
426
  # right perms; the file itself appears at create time.
@@ -7,16 +7,22 @@ description: Generate an agentbox.yaml for the current AgentBox workspace. Invok
7
7
 
8
8
  ## Box layout (what you're configuring against)
9
9
 
10
- Your user i `vscode` and you can use passwordless sudo to run commands as root.
10
+ Your user i `vscode` and you can use `sudo` to run commands as root.
11
11
 
12
- `/workspace` is the box's plain writable filesystem — a per-box git worktree on a fresh `agentbox/<box-name>` branch (or a tar-piped copy of the host workspace for non-git projects). Anything you install or build into `/workspace` (incl. `node_modules`, `.next`, `target`, `.venv`) lives in the **container's writable layer** and is captured wholesale by `agentbox checkpoint` (`docker commit`) — so a setup task that runs the install once becomes a warm-start asset for every future box in the project. Everything is wiped on `agentbox destroy`.
12
+ `/workspace` is where the user code lives, a per-box git worktree on a fresh `agentbox/<box-name>` branch (or a tar-piped copy of the host workspace for non-git projects).
13
+ Run `agentbox checkpoint --set-default` (similar to `docker commit`) to save any changes make to the system and workspace so that new boxes will start from a warm state. Everything is wiped on `agentbox destroy`.
13
14
 
14
- Three bind mounts wire the box back to the host:
15
+ Some special folders:
15
16
 
16
- - **Host main repo's `.git/`** — bind-mounted RW at its identical absolute host path. In-box commits land on the host's branch refs (visible to `git log` on the host immediately); the box itself carries no SSH/git creds, so `git push` goes through the host relay (`agentbox-ctl git push`). The host's **working tree is never written to** — only refs/objects under `.git/`.
17
- - **`~/.claude`** — a Docker named volume (`agentbox-claude-config`, shared across boxes by default) seeded from the host's `~/.claude` on each create so auth, skills, and plugins persist without leaking the host's home dir.
17
+ - **Host main repo's `.git/`** — If the box bind-mounted RW at its identical absolute host path. In-box commits land on the host's branch refs (visible to `git log` on the host immediately); the box itself carries no SSH/git creds, so `git push` goes through the host relay (`agentbox-ctl git push`). The host's **working tree is never written to** — only refs/objects under `.git/`.
18
+ - **`~/.claude`** — and similar home folders for coding agents are seeded from the host's `~/.claude` on each create so auth, skills, and plugins persist without leaking the host's home dir.
18
19
  - **`agentbox.yaml`** — read by `agentbox-ctl` from `/workspace`. Tasks and services declared here are what the supervisor will run.
19
20
 
21
+ Exposed ports and services:
22
+ - **portless** - every port with `expose:` setting in agentbox.yaml, will be exposed not only as a local port but also as a special domain name `https://<name>.localhost` (so on https) using `portless` cli and proxy. This will be also mapped to the host where also `portless` proxy is running so users can access the same service on the same looking url.
23
+ - **vnc** - the webVNC server exposed on 6080 will be proxies to the host on a random port.
24
+ - **vscode** - the vscode server is proxied to the host on a random port.
25
+
20
26
  ## Goal
21
27
 
22
28
  Produce a `/workspace/agentbox.yaml` that captures this project's services, tasks, and box defaults so the in-box supervisor (`agentbox-ctl`) can boot the workspace deterministically.
@@ -64,7 +70,7 @@ The box's primary web app (the dev server / Next.js / API the user opens in a br
64
70
  as: 80 # must be 80 — the container port AgentBox publishes
65
71
  ```
66
72
 
67
- At most **one** service may set `expose:`. AgentBox forwards container `:80` to `127.0.0.1:<port>` and publishes it on the host, so `agentbox list`/`status` show it as the box's main URL on every engine (no OrbStack dependency). Set this on the same service whose `ready_when:` you just wrote (a DB or worker should **not** get `expose:`).
73
+ At most **one** service may set `expose:`. AgentBox forwards container `:80` to `127.0.0.1:<port>` and publishes it on the host with `portless` proxy to a <boxname>.localhost url, so `agentbox list`/`status` show it as the box's main URL on every engine (no OrbStack dependency). Set this on the same service whose `ready_when:` you just wrote (a DB or worker should **not** get `expose:`).
68
74
 
69
75
  ## 4. Restart + backoff
70
76
 
@@ -158,24 +164,33 @@ services:
158
164
  - A service with `restart: never` and an autostart dependency will block the dependent forever after one failed run — usually a mistake.
159
165
  - `command:` is either a shell string (run via `bash -c`) or an argv array. Use the argv form if you need to avoid shell quoting.
160
166
 
161
- ## 8. Hand-off
167
+ ## 8. Checkpoint the warm state (do this at the very end)
168
+
169
+ Checkpoint (snapshot) this box writable layer: once the box is warmed up (deps installed, services ready), checkpoint it with `agentbox-ctl checkpoint --name setup --replace --set-default` so future boxes start ready.
170
+ Run this command exactly once. The `--name setup --replace` makes it idempotent — if it ever needs to run again it overwrites the existing `setup` checkpoint instead of stacking duplicates.
171
+ This doesn't need to be confirmed by the user.
172
+ It will pause the container for several seconds so warn the user about it and write Done when it's done.
173
+
174
+ ## 9. Hand-off
162
175
 
163
- 1. Write the file to `/workspace/agentbox.yaml`.
164
- 2. **Apply it live**: from inside the box run `agentbox-ctl reload`. The already-running supervisor re-reads the config and immediately runs the declared tasks and autostarts the services — no box restart needed. It prints the `added` / `removed` / `changed` diff. If it errors because the daemon isn't running, the config is still valid: the next `agentbox start` (or `agentbox create` in this workspace) picks it up automatically.
165
- 3. Confirm with `agentbox-ctl status`: tasks should be `running` or `done`, autostart services `starting` or `ready`. If something failed, tail it with `agentbox-ctl logs <service>` and fix the config, then `agentbox-ctl reload` again.
166
- 4. Checkpoint (snapshot) this box writable layer: once the box is warmed up (deps installed, services ready), checkpoint it with `agentbox-ctl checkpoint --set-default` so future boxes start ready.
176
+ Tell the user (verbatim):
167
177
 
168
- 5. Tell the user:
178
+ ```
179
+ █████╗ ██████╗ ███████╗███╗ ██╗████████╗██████╗ ██████╗ ██╗ ██╗
180
+ ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝██╔══██╗██╔═══██╗╚██╗██╔╝
181
+ ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ██████╔╝██║ ██║ ╚███╔╝
182
+ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ██╔══██╗██║ ██║ ██╔██╗
183
+ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ██████╔╝╚██████╔╝██╔╝ ██╗
184
+ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝
185
+ ```
169
186
 
170
- > I wrote `/workspace/agentbox.yaml` and ran `agentbox-ctl reload` so the supervisor is already running the declared tasks/services. To land the file on the host:
171
- > - I've created a checkpoint of the warm box state so future boxes start ready in seconds, no reinstall.
172
- > - commit it inside the box (`git add agentbox.yaml && git commit -m 'add agentbox config'`) — the box's `.git/` is bind-mounted, so the commit shows up on the host immediately; or
173
- > - on the host, tell the user to run `agentbox download config` to update their original host workspace.
187
+ your box is ready, you can start more sessions with `agentbox claude`
188
+ you can access the web app at https://<boxname>.localhost
174
189
 
175
- ## 9. Known issues
190
+ ## 10. Known issues
176
191
 
177
192
  - For Nextjs/Vite/Tasnstack projects, makes sure to forward also websocket for hot reload.
178
193
 
179
- - The `install` task is intentionally a no-op once `node_modules/.agentbox-installed` exists. Do **not** remove the marker guard to "force a fresh install" — that reinstalls on every box start. To force a one-off rebuild, delete `node_modules` (or just the marker) then run `agentbox-ctl reload`.
194
+ - Service like flask, nextjs, BETTER_AUTH_URL, NEXT_PUBLIC_APP_URL should use the <boxname>.localhost url for the local development so that on the host it will use the same url as the box.
180
195
 
181
- - Host-only CLI wrappers (portless, etc.) must be bypassed, eg some projects wrap the dev server with a host-side proxy (here: `portless projectname next dev --turbopack`). Override the service command: to call the underlying tool directly (`next dev --turbopack`)
196
+ - The `install` task is intentionally a no-op once `node_modules/.agentbox-installed` exists. Do **not** remove the marker guard to "force a fresh install" that reinstalls on every box start. To force a one-off rebuild, delete `node_modules` (or just the marker) then run `agentbox-ctl reload`.