@madarco/agentbox 0.15.0 → 0.17.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.
- package/CHANGELOG.md +68 -0
- package/dist/{_cloud-attach-R6TRWG5L.js → _cloud-attach-SGNR6BXP.js} +5 -4
- package/dist/{chunk-BKU34KYY.js → chunk-3JXSW6PN.js} +42 -24
- package/dist/chunk-3JXSW6PN.js.map +1 -0
- package/dist/{chunk-RSKG7AFU.js → chunk-46NXCJ6Z.js} +45 -34
- package/dist/{chunk-RSKG7AFU.js.map → chunk-46NXCJ6Z.js.map} +1 -1
- package/dist/{chunk-43Q5GWP6.js → chunk-5AKAC27L.js} +7 -7
- package/dist/{chunk-XKH7NTT7.js → chunk-6QFPYU4Z.js} +248 -5
- package/dist/chunk-6QFPYU4Z.js.map +1 -0
- package/dist/{chunk-MLMFNN4T.js → chunk-HFQZJO73.js} +688 -197
- package/dist/chunk-HFQZJO73.js.map +1 -0
- package/dist/{chunk-E7CHS7ZR.js → chunk-KTDJ5JTE.js} +18 -6
- package/dist/chunk-KTDJ5JTE.js.map +1 -0
- package/dist/{chunk-72CJTXN6.js → chunk-RXPV3OIX.js} +80 -72
- package/dist/chunk-RXPV3OIX.js.map +1 -0
- package/dist/chunk-WJFZJZIM.js +24 -0
- package/dist/{chunk-MCOU6CZS.js → chunk-XWBFWUY2.js} +30 -22
- package/dist/chunk-XWBFWUY2.js.map +1 -0
- package/dist/{cloud-poller-SUNA6ZQC-2RG5WPRN.js → cloud-poller-SUNA6ZQC-7M5LJHHE.js} +2 -1
- package/dist/{dist-S4XR4ACV.js → dist-433ASGVG.js} +6 -5
- package/dist/{dist-S4XR4ACV.js.map → dist-433ASGVG.js.map} +1 -1
- package/dist/{dist-JZ3XO6EB.js → dist-BO2R55FX.js} +6 -5
- package/dist/{dist-JZ3XO6EB.js.map → dist-BO2R55FX.js.map} +1 -1
- package/dist/{dist-AGTIA7AD.js → dist-CNABE32V.js} +7 -6
- package/dist/{dist-AGTIA7AD.js.map → dist-CNABE32V.js.map} +1 -1
- package/dist/{dist-FIFEFKJ7.js → dist-TEKY3GFT.js} +6 -5
- package/dist/{dist-FIFEFKJ7.js.map → dist-TEKY3GFT.js.map} +1 -1
- package/dist/{dist-OGJGZETZ.js → dist-VAATGBAR.js} +6 -5
- package/dist/index.js +2426 -2094
- package/dist/index.js.map +1 -1
- package/dist/{prepared-state-MQHD3M5F-Q27AZU53.js → prepared-state-MQHD3M5F-OVABNV66.js} +3 -2
- package/dist/prepared-state-MQHD3M5F-OVABNV66.js.map +1 -0
- package/package.json +5 -4
- package/runtime/docker/Dockerfile.box +21 -2
- package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +82 -29
- package/runtime/docker/packages/ctl/dist/bin.cjs +10675 -9191
- package/runtime/docker/packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup +5 -2
- package/runtime/docker/packages/sandbox-docker/scripts/linear-shim +181 -0
- package/runtime/docker/packages/sandbox-docker/scripts/ntn-shim +95 -0
- package/runtime/e2b/agentbox-checkpoint-cleanup +5 -2
- package/runtime/e2b/agentbox-setup-skill.md +82 -29
- package/runtime/e2b/ctl.cjs +10675 -9191
- package/runtime/e2b/linear-shim +181 -0
- package/runtime/e2b/ntn-shim +95 -0
- package/runtime/e2b/scripts/build-template.sh +13 -7
- package/runtime/hetzner/agentbox-checkpoint-cleanup +5 -2
- package/runtime/hetzner/agentbox-setup-skill.md +82 -29
- package/runtime/hetzner/ctl.cjs +10675 -9191
- package/runtime/hetzner/linear-shim +181 -0
- package/runtime/hetzner/ntn-shim +95 -0
- package/runtime/hetzner/scripts/install-box.sh +19 -9
- package/runtime/relay/bin.cjs +3696 -2895
- package/runtime/vercel/agentbox-checkpoint-cleanup +5 -2
- package/runtime/vercel/agentbox-setup-skill.md +82 -29
- package/runtime/vercel/ctl.cjs +10675 -9191
- package/runtime/vercel/linear-shim +181 -0
- package/runtime/vercel/ntn-shim +95 -0
- package/runtime/vercel/scripts/provision.sh +13 -7
- package/share/agentbox-setup/SKILL.md +82 -29
- package/share/host-skills/agentbox-info/SKILL.md +1 -1
- package/dist/chunk-72CJTXN6.js.map +0 -1
- package/dist/chunk-BKU34KYY.js.map +0 -1
- package/dist/chunk-E7CHS7ZR.js.map +0 -1
- package/dist/chunk-MCOU6CZS.js.map +0 -1
- package/dist/chunk-MLMFNN4T.js.map +0 -1
- package/dist/chunk-XKH7NTT7.js.map +0 -1
- /package/dist/{_cloud-attach-R6TRWG5L.js.map → _cloud-attach-SGNR6BXP.js.map} +0 -0
- /package/dist/{chunk-43Q5GWP6.js.map → chunk-5AKAC27L.js.map} +0 -0
- /package/dist/{cloud-poller-SUNA6ZQC-2RG5WPRN.js.map → chunk-WJFZJZIM.js.map} +0 -0
- /package/dist/{dist-OGJGZETZ.js.map → cloud-poller-SUNA6ZQC-7M5LJHHE.js.map} +0 -0
- /package/dist/{prepared-state-MQHD3M5F-Q27AZU53.js.map → dist-VAATGBAR.js.map} +0 -0
|
@@ -6,7 +6,8 @@ import {
|
|
|
6
6
|
readPreparedDockerState,
|
|
7
7
|
resolveContextFiles,
|
|
8
8
|
writePreparedDockerState
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6QFPYU4Z.js";
|
|
10
|
+
import "./chunk-WJFZJZIM.js";
|
|
10
11
|
export {
|
|
11
12
|
DOCKERFILE_PATH,
|
|
12
13
|
computeDockerContextFingerprint,
|
|
@@ -15,4 +16,4 @@ export {
|
|
|
15
16
|
resolveContextFiles,
|
|
16
17
|
writePreparedDockerState
|
|
17
18
|
};
|
|
18
|
-
//# sourceMappingURL=prepared-state-MQHD3M5F-
|
|
19
|
+
//# sourceMappingURL=prepared-state-MQHD3M5F-OVABNV66.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@madarco/agentbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.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",
|
|
@@ -60,15 +60,16 @@
|
|
|
60
60
|
"typescript": "^5.7.2",
|
|
61
61
|
"vitest": "^2.1.8",
|
|
62
62
|
"@agentbox/config": "0.0.0",
|
|
63
|
-
"@agentbox/core": "0.0.0",
|
|
64
63
|
"@agentbox/ctl": "0.0.0",
|
|
65
|
-
"@agentbox/
|
|
64
|
+
"@agentbox/core": "0.0.0",
|
|
65
|
+
"@agentbox/integrations": "0.0.0",
|
|
66
66
|
"@agentbox/relay": "0.0.0",
|
|
67
|
+
"@agentbox/sandbox-cloud": "0.0.0",
|
|
67
68
|
"@agentbox/sandbox-core": "0.0.0",
|
|
68
69
|
"@agentbox/sandbox-docker": "0.0.0",
|
|
69
70
|
"@agentbox/sandbox-daytona": "0.0.0",
|
|
70
|
-
"@agentbox/sandbox-hetzner": "0.0.0",
|
|
71
71
|
"@agentbox/sandbox-e2b": "0.0.0",
|
|
72
|
+
"@agentbox/sandbox-hetzner": "0.0.0",
|
|
72
73
|
"@agentbox/sandbox-vercel": "0.0.0"
|
|
73
74
|
},
|
|
74
75
|
"scripts": {
|
|
@@ -72,9 +72,9 @@ RUN apt-get update \
|
|
|
72
72
|
vim \
|
|
73
73
|
libcap2-bin \
|
|
74
74
|
&& rm -rf /var/lib/apt/lists/* \
|
|
75
|
-
&& mkdir -p /workspace /run/agentbox /var/log/agentbox \
|
|
75
|
+
&& mkdir -p /workspace /run/agentbox /var/log/agentbox /var/lib/agentbox \
|
|
76
76
|
&& chmod 755 /workspace \
|
|
77
|
-
&& chown vscode:vscode /workspace /run/agentbox /var/log/agentbox
|
|
77
|
+
&& chown vscode:vscode /workspace /run/agentbox /var/log/agentbox /var/lib/agentbox
|
|
78
78
|
|
|
79
79
|
# The in-box supervisor (runs as non-root `vscode`) owns a TCP forwarder that
|
|
80
80
|
# binds container :80 -> the `expose:`-flagged service (see WebProxy /
|
|
@@ -154,6 +154,25 @@ COPY packages/sandbox-docker/scripts/gh-shim /usr/local/bin/gh
|
|
|
154
154
|
COPY packages/sandbox-docker/scripts/git-shim /usr/local/bin/git
|
|
155
155
|
RUN chmod +x /usr/local/bin/gh /usr/local/bin/git
|
|
156
156
|
|
|
157
|
+
# `ntn` (Notion CLI) shim — same shape as gh-shim, routes a strict subset
|
|
158
|
+
# of `ntn` subcommands through the host relay (the host's `ntn` runs the
|
|
159
|
+
# call; the box never sees the Notion token). Symlinked as `notion` per
|
|
160
|
+
# docs/integrations_backlog.md's per-service surface naming. Disabled by
|
|
161
|
+
# default; flip `integrations.notion.enabled` to enable. See
|
|
162
|
+
# packages/sandbox-docker/scripts/ntn-shim and docs/notion_backlog.md.
|
|
163
|
+
COPY packages/sandbox-docker/scripts/ntn-shim /usr/local/bin/ntn
|
|
164
|
+
RUN chmod +x /usr/local/bin/ntn && ln -s /usr/local/bin/ntn /usr/local/bin/notion
|
|
165
|
+
|
|
166
|
+
# `linear` (Linear CLI — @schpet/linear-cli) shim — same shape as ntn-shim,
|
|
167
|
+
# routes a strict subset of `linear` subcommands through the host relay
|
|
168
|
+
# (the host's `linear` runs the call; the box never sees the Linear API
|
|
169
|
+
# token). `linear auth token` (which would print the raw token to stdout)
|
|
170
|
+
# is explicitly rejected by the shim. Disabled by default; flip
|
|
171
|
+
# `integrations.linear.enabled` to enable. See
|
|
172
|
+
# packages/sandbox-docker/scripts/linear-shim and docs/linear_backlog.md.
|
|
173
|
+
COPY packages/sandbox-docker/scripts/linear-shim /usr/local/bin/linear
|
|
174
|
+
RUN chmod +x /usr/local/bin/linear
|
|
175
|
+
|
|
157
176
|
# Setup guide for the first-run wizard. This baked copy is the single source
|
|
158
177
|
# of the /agentbox-setup skill: seedSetupSkillIntoVolume()
|
|
159
178
|
# (packages/sandbox-docker/src/claude.ts) copies it into the box's
|
|
@@ -46,35 +46,56 @@ Look at `/workspace`:
|
|
|
46
46
|
- **Tasks** = one-shot. `pnpm install`, DB migrations, codegen, fixture loaders, install apt packages. Wire dependent services with `needs:` so they wait for the task to finish successfully.
|
|
47
47
|
- Names: must match `[A-Za-z0-9_-]+`. Task names and service names share a namespace — no collisions.
|
|
48
48
|
- No cycles in `needs:`.
|
|
49
|
-
- **Always generate a dependency-install task** and make it the root of the `needs:` graph (every service that needs deps gets `needs: [install, …]`). Future boxes start from a snapshot of the final filesystem so they won't need this, but updates or moving to a cloud provider might need to rebuild the container from scratch. The filesystem can be then later captured by `agentbox-ctl checkpoint --set-default`. The task must be **idempotent
|
|
49
|
+
- **Always generate a dependency-install task** and make it the root of the `needs:` graph (every service that needs deps gets `needs: [install, …]`). Future boxes start from a snapshot of the final filesystem so they won't need this, but updates or moving to a cloud provider might need to rebuild the container from scratch. The filesystem can be then later captured by `agentbox-ctl checkpoint --set-default`. The task must be **idempotent**: `agentbox-ctl` re-runs pending tasks on every box stop/start (the daemon dies with the container and is relaunched), so an unguarded install would reinstall on every start. The clean way is the **`run_once: true`** field — the supervisor stores a marker keyed by a hash of the command and skips warm boots automatically (the marker lives at `/var/lib/agentbox/tasks/<name>`, on the box rootfs, captured by checkpoints, never polluting `/workspace`). Editing the command re-runs it. Detect the package manager from the lockfile — never hardcode `pnpm`. See the worked example below.
|
|
50
50
|
- **Add a comment to the beginning** of the file to explain what you did and what issues you encountered, so that future run might use this information in case the project evolves and you need to update the agentbox.yaml file.
|
|
51
51
|
|
|
52
52
|
### Stateful services: data persistence & re-seeding (read this for databases)
|
|
53
53
|
|
|
54
|
+
**Declare a containerized dependency with the `image:` service form** — AgentBox
|
|
55
|
+
generates the `docker start`-or-`run` shell (no hand-written `docker run … || docker
|
|
56
|
+
start …`). The container runs in the box's dockerd; a published port is reachable
|
|
57
|
+
from other in-box services at `127.0.0.1:<host port>`:
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
services:
|
|
61
|
+
postgres:
|
|
62
|
+
image: # bare string (image: postgres:17-alpine) or a mapping:
|
|
63
|
+
name: postgres:17-alpine
|
|
64
|
+
ports: ["5432:5432"]
|
|
65
|
+
env:
|
|
66
|
+
POSTGRES_PASSWORD: postgres
|
|
67
|
+
POSTGRES_DB: app
|
|
68
|
+
args: "-c max_connections=200" # string or ["-c","max_connections=200"]
|
|
69
|
+
container_name: app_db # optional; default = service name
|
|
70
|
+
ready_when: { port: 5432 }
|
|
71
|
+
restart: always
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The container is reused by name across box stop/start. (Changing `image`/`env`
|
|
75
|
+
reuses the existing container as-is; `docker rm <container_name>` + `agentbox-ctl
|
|
76
|
+
reload` to apply.) Install the DB client the migrate/seed tasks need (e.g.
|
|
77
|
+
`postgresql-client`) in the `install` task and reach the DB over TCP — don't
|
|
78
|
+
`docker exec` the container (nested exec fails with a `setns` error in a box).
|
|
79
|
+
|
|
54
80
|
**A checkpoint does NOT capture docker-in-docker data.** `agentbox checkpoint` is a `docker commit` of the box's writable filesystem (the system + `/workspace`). The in-box `dockerd` keeps its storage in a *separate* per-box volume (`/var/lib/docker`), which is **not** part of that image — it's fresh on every new box and wiped on `agentbox destroy`. So a database or cache you run as a **docker container** (e.g. `docker run … postgres`) starts **empty on every new box** created from a checkpoint (every `agentbox claude` / `agentbox create`), even though `/workspace` and any marker files you wrote were restored. (A DB run as a **native process** with its data dir on the box filesystem — e.g. `postgres -D /var/lib/postgresql/data` — *is* captured by the checkpoint, since it lives in the writable layer.)
|
|
55
81
|
|
|
56
|
-
**Consequence for migrate/seed tasks of a containerized DB: do
|
|
82
|
+
**Consequence for migrate/seed tasks of a containerized DB: do NOT use `run_once: true` (the marker form).** A command-hash marker is correct for deps (they live in `/workspace`, which the checkpoint captures), but **wrong** for DB data living in a docker volume: the marker is restored from the checkpoint while the DB is empty, so a marker-guarded seed wrongly skips and the app boots against an empty database. Instead use the **`run_once: { check: <cmd> }`** form — the probe runs first and the seed runs unless the probe exits 0, and **no marker is written** (the DB is the source of truth). Gate on the actual data:
|
|
57
83
|
|
|
58
84
|
```yaml
|
|
59
85
|
seed:
|
|
60
|
-
# Re-seed when the DB is empty. The postgres data lives in the in-box
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
86
|
+
# Re-seed when the DB is empty. The postgres data lives in the in-box docker
|
|
87
|
+
# volume, which is NOT captured by `agentbox checkpoint` — so a box started
|
|
88
|
+
# from a checkpoint has the workspace warm but an empty DB. The marker form
|
|
89
|
+
# would be restored while the DB is blank and wrongly skip; the `check` probe
|
|
90
|
+
# gates on the data itself. Exit 0 = already seeded, skip. Fast no-op once
|
|
65
91
|
# the data is present.
|
|
66
|
-
command:
|
|
67
|
-
set -e
|
|
68
|
-
export PGPASSWORD=postgres
|
|
69
|
-
# Probe for existing data. If the table is missing the query errors,
|
|
70
|
-
# stderr is suppressed, stdout is empty, the grep fails — so we seed.
|
|
71
|
-
if psql -h 127.0.0.1 -p 5432 -U postgres -d app -tAc \
|
|
72
|
-
"SELECT EXISTS (SELECT 1 FROM users LIMIT 1)" 2>/dev/null | grep -q t; then
|
|
73
|
-
echo "data present — skip seed"
|
|
74
|
-
exit 0
|
|
75
|
-
fi
|
|
76
|
-
pnpm db:seed
|
|
92
|
+
command: pnpm db:seed
|
|
77
93
|
needs: [install, migrate]
|
|
94
|
+
run_once:
|
|
95
|
+
check: |
|
|
96
|
+
export PGPASSWORD=postgres
|
|
97
|
+
psql -h 127.0.0.1 -p 5432 -U postgres -d app -tAc \
|
|
98
|
+
"SELECT EXISTS (SELECT 1 FROM users LIMIT 1)" 2>/dev/null | grep -q t
|
|
78
99
|
```
|
|
79
100
|
|
|
80
101
|
**Lifecycle nuance (this is why the data check, not a marker, is right):**
|
|
@@ -148,22 +169,19 @@ tasks:
|
|
|
148
169
|
# Idempotent install. /workspace is the container's writable filesystem, so
|
|
149
170
|
# node_modules persists across pause/stop/start and is captured by
|
|
150
171
|
# `agentbox checkpoint`. The host's node_modules is macOS-native and is
|
|
151
|
-
# never copied in, so
|
|
152
|
-
# on every subsequent box start (
|
|
153
|
-
#
|
|
154
|
-
# manager.
|
|
172
|
+
# never copied in, so the first Linux install runs; `run_once: true` then
|
|
173
|
+
# skips it on every subsequent box start (the supervisor stores a marker
|
|
174
|
+
# keyed by a hash of the command). Adjust the lockfile detection to the
|
|
175
|
+
# project's package manager.
|
|
155
176
|
install:
|
|
156
177
|
command: |
|
|
157
178
|
set -e
|
|
158
|
-
|
|
159
|
-
[ -f "$MARKER" ] && { echo "deps installed (marker present) — skip"; exit 0; }
|
|
160
|
-
apt-get update && apt-get install -y postgresql-client
|
|
161
|
-
rm -rf node_modules
|
|
179
|
+
sudo apt-get update && sudo apt-get install -y postgresql-client
|
|
162
180
|
if [ -f pnpm-lock.yaml ]; then
|
|
163
181
|
corepack enable >/dev/null 2>&1 || true
|
|
164
182
|
pnpm install --frozen-lockfile || pnpm install
|
|
165
183
|
fi
|
|
166
|
-
|
|
184
|
+
run_once: true
|
|
167
185
|
|
|
168
186
|
migrate:
|
|
169
187
|
command: pnpm db:migrate
|
|
@@ -258,6 +276,41 @@ On Vercel: this actually STOPS the sandbox, so warn the user about it. Also the
|
|
|
258
276
|
|
|
259
277
|
- For Nextjs/Vite/Tasnstack projects, makes sure to forward also websocket for hot reload.
|
|
260
278
|
|
|
261
|
-
- Service like flask, nextjs, BETTER_AUTH_URL, NEXT_PUBLIC_APP_URL should use the
|
|
279
|
+
- 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. Render this automatically instead of hand-writing `sed` — see section 6c.
|
|
280
|
+
|
|
281
|
+
- The `install` task above uses `run_once: true`, so it is a no-op on warm boots. Do **not** wrap it in a manual marker check too. To force a one-off rebuild, run `agentbox-ctl run-task install --force` (which bypasses the run_once marker), or edit the command (a changed command invalidates the hash and re-runs).
|
|
282
|
+
|
|
283
|
+
## 11. Pin URLs / render config files (env, secrets)
|
|
284
|
+
|
|
285
|
+
Many apps hard-code a hostname (e.g. `optima.localhost`) or read a gitignored `.env`. Instead of long `sed` commands in a task, use the built-ins:
|
|
286
|
+
|
|
287
|
+
- **`agentbox-ctl render <src>`** — a declarative `sed` for files already in the workspace. `--env` substitutes `{{AGENTBOX_*}}` placeholders; `--rules <name>` applies a named rule-set from the top-level `replacements:` block; `--rule 'from=>to'` / `--rule-regex 'pat=>repl'` are inline. Write to `--out <path>` (or `--in-place`). The whitelist placeholders are `{{AGENTBOX_BOX_NAME}}`, `{{AGENTBOX_BOX_HOST}}` (= `<boxname>.localhost`), `{{AGENTBOX_BOX_ID}}`, `{{AGENTBOX_BOX_KIND}}`, `{{AGENTBOX_HOST_WORKSPACE}}`, `{{AGENTBOX_PROJECT_ROOT}}`.
|
|
288
|
+
|
|
289
|
+
Render a gitignored `.env` from a committed `env.example` on every boot, pinning the URLs to this box:
|
|
290
|
+
|
|
291
|
+
```yaml
|
|
292
|
+
replacements:
|
|
293
|
+
box-host:
|
|
294
|
+
- { from: 'optima\.localhost', to: '{{AGENTBOX_BOX_HOST}}', regex: true } # {{AGENTBOX_BOX_HOST}} = <box>.localhost
|
|
295
|
+
|
|
296
|
+
tasks:
|
|
297
|
+
env:
|
|
298
|
+
# The render is idempotent (the rules re-pin the same lines every boot), so
|
|
299
|
+
# no `run_once:` guard is needed — it self-corrects on a checkpoint-started
|
|
300
|
+
# box that carries a different box's host in .env.
|
|
301
|
+
command: agentbox-ctl render apps/saas/env.example --out apps/saas/.env --env --rules box-host
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Note: an `run_once: { check: <cmd> }` probe runs verbatim via `bash -c` with the box env — use shell vars like `$AGENTBOX_BOX_NAME`, NOT `{{…}}` placeholders (those are only expanded by `render`/carry, never by the supervisor).
|
|
305
|
+
|
|
306
|
+
**Generated secrets:** put `{{AGENTBOX_AUTO_SECRET}}` in the template for a value like `BETTER_AUTH_SECRET` instead of shelling out to `openssl rand`. Unnamed → a fresh 32-byte base64url secret each render (stable when you render the template→`.env` once). `{{AGENTBOX_AUTO_SECRET:better-auth}}` → generated once, persisted at `/var/lib/agentbox/secrets/<name>`, reused on every render (stable even if you render every boot). Example `env.example` line: `BETTER_AUTH_SECRET="{{AGENTBOX_AUTO_SECRET:better-auth}}"`.
|
|
307
|
+
|
|
308
|
+
- **`carry:` + `replaceEnvs`/`replace`/`rules`** — for a host-only file (e.g. a real `.env` with secrets that never lives in the repo), carry it in and render it host-side in one step (file entries only):
|
|
262
309
|
|
|
263
|
-
|
|
310
|
+
```yaml
|
|
311
|
+
carry:
|
|
312
|
+
- src: ~/secrets/optima.env
|
|
313
|
+
dest: /workspace/apps/saas/.env
|
|
314
|
+
replaceEnvs: true
|
|
315
|
+
rules: [box-host]
|
|
316
|
+
```
|