Reference
Scripts
The scripts an Operator runs by hand, and what each one checks, writes or changes. Package scripts are run from the repository root unless a command says otherwise.
pnpm sse:check
Proves a reverse proxy is not buffering the Conversation stream. Takes one optional
argument: the base URL to test, defaulting to http://127.0.0.1:8080. A
trailing slash is stripped.
It reads /api/stream-check, which needs no account and no Provider key, and
measures when each chunk arrives relative to the first. Buffering is the failure
mode nobody notices: no error, no warning, the whole reply simply arrives at once
at the end.
It prints the chunk count, the first-byte time, the last-byte time and the
spread between them, then PASS or FAIL. It exits non-zero when:
Run it against your own edge, not only against the server directly: testing
127.0.0.1:8080 proves the application streams, and proves nothing about the
proxy in front of it. See Reverse proxy.
pnpm sandbox:check
Asserts, from the outside, that a Sandbox is actually isolated. Each claim is something a Dockerfile change or a stray flag could quietly undo, and none of them fails loudly when it does — a Sandbox that can reach the internet still runs commands fine.
It needs Docker, the Sandbox image, and the internal network. pnpm sandbox:build builds the image (docker build -f deploy/sandbox/Dockerfile -t agentsville-sandbox:latest deploy/sandbox); AGENTSVILLE_SANDBOX_IMAGE overrides which
image the check runs.
It starts two throwaway containers with the same hardening the broker applies —
unprivileged user, all capabilities dropped, no-new-privileges, a 512 process
limit, 2 GB of memory, 1.5 CPUs, a read-only root filesystem and a tmpfs at
/tmp — and then checks ten things:
Every container and volume it created is removed afterwards, whether the checks
passed or not. It prints one PASS or FAIL line per check and exits non-zero
if any failed. See Enabling sandboxes.
pnpm --filter web screenshots
Regenerates the landing page's product screenshots from the running app. These are real captures rather than mockups, so they go stale whenever the interface changes.
It needs both dev servers running — the API on :8080 and the web app on
:3000 — and an account with an NPC and a Conversation in it. Three variables
are required and the script refuses to start without them:
It drives Chromium through Playwright at 1280 by 860, at twice the device pixel
ratio, and captures three screens — a Conversation, the NPC list and the dashboard —
in both light and dark. The six files land in apps/web/public/screenshots/ as
chat-light.png, chat-dark.png, npcs-light.png, npcs-dark.png,
dashboard-light.png and dashboard-dark.png.
The list and dashboard captures are cropped to their content rather than shipping a screen of empty background, the Conversation capture is scrolled to the newest Message first, and the router devtools badge is removed before every shot.
scripts/backup.sh
Dumps the Village database to a gzipped SQL file. Run it from the repository root,
or set AGENTSVILLE_DIR. Intended for host cron:
It takes one optional argument, the destination directory, which overrides
AGENTSVILLE_BACKUP_DIR.
The dump runs mysqldump --single-transaction --routines --triggers inside the
running mysql service, which takes a consistent InnoDB snapshot without
locking the tables, so a backup running mid-Conversation does not stall a live
stream.
Archives are named agentsville-YYYY-MM-DD-HHMM.sql.gz. Each is written as
.sql.gz.partial and renamed only after a clean dump, so a failed run never
leaves a file that looks like a usable backup. The script runs under set -euo pipefail, so any failing step stops it.
See Backup and restore for restoring one.
The db family
pnpm db:migrate reads one variable, DATABASE_URL, deliberately: it goes
straight to the environment rather than through the server's configuration
schema, because a migration has no business refusing to run because a cache is
unconfigured. It prints either No migrations to apply. or
Applied <n>: <names>, and exits non-zero on failure. The server's Dockerfile
chains it ahead of the process with &&, so a failed migration stops the
container rather than letting it serve a schema it does not match.
Migrations take a lock before running, so two containers starting together cannot both apply the same migration. See Database schema.
Valkey has the same three lifecycle scripts under a different name:
pnpm cache:start, pnpm cache:stop and pnpm cache:down.
The docker family
All four use the caddy profile, which adds the bundled reverse proxy. An
Operator running their own proxy uses docker compose directly without that
profile, and Sandboxes need the sandbox profile as well. The web image bakes
its API URL in at build time, so changing where the API lives means a rebuild,
not a restart.
See Install with Docker Compose and Upgrading.