Skip to main content

agentbox-setup

Generate an agentbox.yaml for the current AgentBox workspace. Invoke when the user opens a sandbox without an agentbox.yaml or asks to (re)configure one.

Quellinformationen

Repository
madarco/agentbox
Letzte Quellaktivität
2. September 2026 um 16:32
Erkannte Sprache von SKILL.md
Englisch
Sterne
521
Forks
49

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
agentbox-setup
description
Generate an agentbox.yaml for the current AgentBox workspace. Invoke when the user opens a sandbox without an agentbox.yaml or asks to (re)configure one.
# /agentbox-setup ## Box layout (what you're configuring against) Your user i `vscode` and you can use `sudo` to run commands as root. `/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). 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`. Some special folders: - **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/`. GitHub PR ops (`agentbox-ctl git pr create|view|list|comment|review|merge|close|reopen|checkout`) flow the same way through host `gh`; write ops require host confirmation (deny → exit 10), `merge` and `checkout` have additional opt-in guards. - **`~/.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. - **`agentbox.yaml`** — read by `agentbox-ctl` from `/workspace`. Tasks and services declared here are what the supervisor will run. Exposed ports and services: - **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. - **vnc** - the webVNC server exposed on 6080 will be proxies to the host on a random port. - **vscode** - the vscode server is proxied to the host on a random port. ## Goal 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. `agentbox.yaml` is **declarative**. The supervisor reads it on box start, but you don't have to restart the box: after you write the file, `agentbox-ctl reload` (run from inside the box) makes the already-running supervisor re-read it and immediately run the declared tasks and autostart the services. See step 8. ## 1. Discover the project Look at `/workspace`: - Top-level manifests: `package.json`, `pyproject.toml` / `requirements.txt`, `Cargo.toml`, `go.mod`, `Gemfile`, `composer.json`, `mix.exs`, etc. — these tell you the runtime. - `docker-compose.yaml` / `docker-compose.yml` — often lists the real services the project expects. - `package.json` → `scripts`: look for `dev`, `start`, `build`, `test`, `migrate`, `seed`. - `Makefile` / `justfile` / `Taskfile.yaml` — alternative task runners. - Listening ports: grep for `listen(`, `PORT=`, framework defaults (3000 for Next.js / Nuxt, 5173 for Vite, 8000 for Django, 8080 for Spring, etc.). - Database / cache deps to spin up locally (Postgres, Redis, …) — declare them as services if the project doesn't expect them to be external. ## 2. Pick services and tasks - **Services** = long-running. Web servers, watchers, queue workers, databases. `restart: on-failure` by default. - **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. - Names: must match `[A-Za-z0-9_-]+`. Task names and service names share a namespace — no collisions. - No cycles in `needs:`. - **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. - **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. ### Stateful services: data persistence & re-seeding (read this for databases) **Declare a containerized dependency with the `image:` service form** — AgentBox generates the `docker start`-or-`run` shell (no hand-written `docker run … || docker start …`). The container runs in the box's dockerd; a published port is reachable from other in-box services at `127.0.0.1:<host port>`: ```yaml services: postgres: image: # bare string (image: postgres:17-alpine) or a mapping: name: postgres:17-alpine ports: ["5432:5432"] env: POSTGRES_PASSWORD: postgres POSTGRES_DB: app args: "-c max_connections=200" # string or ["-c","max_connections=200"] container_name: app_db # optional; default = service name ready_when: { port: 5432 } restart: always ``` The container is reused by name across box stop/start. (Changing `image`/`env` reuses the existing container as-is; `docker rm <container_name>` + `agentbox-ctl reload` to apply.) Install the DB client the migrate/seed tasks need (e.g. `postgresql-client`) in the `install` task and reach the DB over TCP — don't `docker exec` the container (nested exec fails with a `setns` error in a box). **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.) **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: ```yaml seed: # Re-seed when the DB is empty. The postgres data lives in the in-box docker # volume, which is NOT captured by `agentbox checkpoint` — so a box started # from a checkpoint has the workspace warm but an empty DB. The marker form # would be restored while the DB is blank and wrongly skip; the `check` probe # gates on the data itself. Exit 0 = already seeded, skip. Fast no-op once # the data is present. command: pnpm db:seed needs: [install, migrate] run_once: check: | export PGPASSWORD=postgres psql -h 127.0.0.1 -p 5432 -U postgres -d app -tAc \ "SELECT EXISTS (SELECT 1 FROM users LIMIT 1)" 2>/dev/null | grep -q t ``` **Lifecycle nuance (this is why the data check, not a marker, is right):** - **Box stop → start** (`agentbox stop`/`start`): the supervisor daemon dies with the container and is relaunched, so it **re-runs all tasks** from `pending`. The per-box docker volume *does* survive stop/start, so the DB still has data — the data check makes the seed a fast no-op. - **New box from a checkpoint** (`agentbox claude`/`create`): tasks run and the DB volume is empty → the check fails → the seed runs. Correct. - **Resume after pause** (`agentbox pause`/`unpause`): the daemon is frozen and thawed, **not** restarted, so tasks do **not** re-run at all — nothing to seed, the running DB is untouched. (Migrations are usually safe to re-run as-is: migration tools track applied migrations in their own table, which on a fresh box is empty, so they simply re-apply. Only the *data* seed needs the existence check.) Install the DB client the seed/migrate tasks need (e.g. `postgresql-client`) in the `install` task — don't `docker exec` the DB container for these checks (nested `docker exec` fails inside a box with a `setns` error); reach it over TCP with the client tools instead. ## 3. Wire readiness probes (services only) `ready_when:` lets the supervisor decide when a service is "ready" (vs. just "running"). Exactly one of these must be present: - `port: 3000` — TCP connect (default host `127.0.0.1`; override with `host:`). - `log_match: "Listening on"` — regex matched against stdout/stderr. First match flips the service to ready. - `http: "http://127.0.0.1:3000/health"` — GET probe. Optional `expect_status: 200` (default: any 2xx). Tunables: `interval_ms` (default 500), `initial_delay_ms` (default 0), `timeout_ms` (default 60000), `on_timeout: kill | mark_unhealthy` (default `kill` — re-enters the restart policy). ### Mark the web service with `expose:` The box's primary web app (the dev server / Next.js / API the user opens in a browser) should declare: ```yaml expose: port: 3000 # the port this service listens on inside the box as: 80 # must be 80 — the container port AgentBox publishes ``` 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:`). ### If the box hosts a SERVICE AGENT (openclaw), the units are already there A service agent — `agentbox openclaw` today — is a daemon AgentBox itself runs. Its supervisor units (an `openclaw-onboard` one-shot, an `openclaw-render`, and the `openclaw gateway` service with `ready_when: { http: /healthz }` and `expose: { port: 18789, as: 80 }`) are synthesized from the agent's own catalog row and folded in at boot. **Do not write them into `agentbox.yaml`** — a unit of the same name in the workspace file WINS and would replace the one the agent ships. Two things you may still need to write: - **A different web app on `:80`.** Only ONE service may `expose:`. If the project has its own web service that must be the box URL, the agent's `expose:` is dropped with a warning — decide which one the user wants and keep exactly one. - **The `openclaw:` overlay block** (see §11a below), for gateway config the user wants under version control. ## 4. Restart + backoff Per service: - `restart: always | on-failure | never` (default `on-failure`). - `backoff:` — `initial_ms` (default 500), `max_ms` (default 30000; must be `>= initial_ms`), `factor` (default 2). ## 5. (Optional) `defaults:` block Sets per-project defaults for `agentbox create`/`claude`/`code`/`shell` — same shape as `~/.agentbox/config.yaml`. CLI flags still override. Common keys: - `box.hostSnapshot` (bool) — APFS-clone the *host* workspace into a per-box scratch dir before seeding `/workspace` (stabilizes the tar-pipe source). - `box.defaultCheckpoint` (string) — checkpoint new boxes start from (normally you set this via `agentbox-ctl checkpoint --set-default` at the end of setup — see section 9, not by hand). - `box.withPlaywright` (bool) — install `@playwright/cli` globally inside the box. - `box.vnc` (bool) — run Xvnc + noVNC on container port 6080. - `box.isolateClaudeConfig` (bool) — per-box `~/.claude` volume instead of the shared one. - `code.ide` — `vscode | cursor | auto`. - `code.autoTerminals` (bool) — auto-generate `.vscode/tasks.json` with per-service tails. - `browser.default` — `agent-browser | playwright | both`. Full key list (run on the host): `agentbox config list --keys`. ## 6. Worked example ```yaml # yaml-language-server: $schema=https://agent-box.sh/schema/agentbox.schema.json # This agentbox.yaml setup this Next.js project, and includes: # - a postgres database because it's used in the project # - an inngest server for queues # - a fix to move .turbo/cache folder to the workspace to avoid a permission error during setup # - ... defaults: box: withPlaywright: true code: ide: cursor tasks: # Idempotent install. /workspace is the container's writable filesystem, so # node_modules persists across pause/stop/start and is captured by # `agentbox checkpoint`. The host's node_modules is macOS-native and is # never copied in, so the first Linux install runs; `run_once: true` then # skips it on every subsequent box start (the supervisor stores a marker # keyed by a hash of the command). Adjust the lockfile detection to the # project's package manager. install: command: | set -e sudo apt-get update && sudo apt-get install -y postgresql-client if [ -f pnpm-lock.yaml ]; then corepack enable >/dev/null 2>&1 || true pnpm install --frozen-lockfile || pnpm install fi run_once: true migrate: command: pnpm db:migrate needs: [install] services: postgres: command: postgres -D /var/lib/postgresql/data ready_when: port: 5432 restart: always dev: command: pnpm dev needs: [install, migrate, postgres] ready_when: port: 3000 timeout_ms: 120000 expose: port: 3000 as: 80 restart: on-failure backoff: initial_ms: 500 max_ms: 5000 factor: 2 ``` ## 6b. Bringing extra host files/folders into the box Two ways to copy host files in (both COPY — never a live mount, so the box can't write back to the host): - **`carry:` block** (declarative, in `agentbox.yaml`) — for files/dirs every box should get at create time. Each entry is `{ src, dest }` with optional `mode`, `user`, `optional`, and `exclude:` (a list of tar globs / bare dir names to drop when copying a directory). Heavy regenerable dirs (`.git`, `node_modules`, `bin`, `obj`, `packages`, `dist`, `.next`, `target`) are dropped by default; `exclude:` is additive. Each carry entry is capped at `box.cpMaxBytes` (default 100 MiB after excludes) — the same limit `agentbox cp` enforces. - **`agentbox-ctl cp fromHost <hostPath...> <boxPath>`** (ad-hoc, from inside the box) — for a one-off copy. Takes several sources in one call (last path is the dest, which must be a directory). Prompts the user on the host to approve. **The per-copy size limit (important for large/legacy folders).** A single copy is blocked above `box.cpMaxBytes` (default **100 MB**) *after* default excludes, so it fails loud instead of silently hanging. When blocked you get a `du`-style tree of the biggest remaining folders/subfolders. To get under the limit, EITHER: - **drop what the box can regenerate** (the default excludes already remove `node_modules`/`.git`/build output; add more with `--exclude=<glob-or-name>`), OR - **copy the heavy folders one at a time** so each copy is under the limit, OR - pass `--yes` to copy the whole thing anyway (only when you really need it all). Example: a 2.4 GB legacy folder is mostly `packages/` (NuGet) + `.git`; those are excluded by default, and what's left can be copied in one call by listing the sub-folders into a destination directory: `agentbox-ctl cp fromHost ../legacy/src ../legacy/Database /workspace/legacy/`. ## 7. Validate before handing off - check with `agentbox-ctl reload` and then `agentbox-ctl status` that everything is running as expected. - Every name in `needs:` must reference an existing task or service. - A service with `restart: never` and an autostart dependency will block the dependent forever after one failed run — usually a mistake.
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen