You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
All scripts are run from the repo root with bun run NAME and require Bun 1.3.13 or newer — this is the interface for a from-source host checkout (including the host dev loop). For a docker compose deployment, the equivalent ops surface is the coderunner CLI baked into the control image; see Containerized ops: the coderunner CLI below.
Running the App
Script
What it does
start
Applies pending database migrations, then starts the control plane. The normal way to run CodeRunner from source.
demo
Applies migrations, then starts the control plane in demo mode (--demo), from source. Auth is bypassed and every visitor shares one admin workspace — for local evaluation only. See Quick Start (Installation).
demo:docker
Runs the containerized demo stack: SCRIPTUM_DEMO_MODE=1 docker compose up. The containerized equivalent of demo.
dev:control
Starts the control plane with --watch so it restarts automatically when source files change. Use during backend development. Always runs in port mode, regardless of FRC_CONTAINER_NETWORK.
dev:web
Starts the Vite dev server for the React web shell with HMR. Use alongside dev:control during frontend development.
Containerized ops: the coderunner CLI
In a docker compose deployment the scripts documented on this page are baked
into the control image and reachable through one dispatching entrypoint,
coderunner <subcommand>, installed at /usr/local/bin/coderunner
(containers/control/entrypoint.sh). Two invocation forms work, for different
reasons:
docker compose exec control coderunner <subcommand> — runs inside the
already-running control container. exec bypasses the image
ENTRYPOINT entirely, so this form only works because coderunner is also
installed on PATH, not because it's the entrypoint.
docker compose run --rm control <subcommand> — starts a fresh one-off
container from the same image; run replaces CMD, so the entrypoint
itself does the dispatching. Use this form when the control plane is
stopped (for example, restore), since exec requires a running container.
coderunner subcommand
Equivalent bun run script (from-source)
What it does
serve (default; also plain docker compose up)
start
Applies migrations, then starts the server as PID 1.
Passed through verbatim (exec "$@") — for example, docker compose run --rm control bash opens a shell.
Example: bun run users:list on a from-source checkout is
docker compose exec control coderunner users list in a compose deployment.
There is no admin bootstrap step here at all — admin access is a Legion group
membership, granted entirely in Legion's own /admin/groups; see
Legion Setup.
Build
Script
What it does
build
Full production build: builds the React web shell, AdvantageScope Lite, and Choreo's web frontend, then pulls the workspace Docker image from GHCR. Run this before start on a fresh checkout. Does not build Elastic Dashboard (see build:elastic) — a missing Elastic dist just leaves /elastic/ serving a 503.
build:web
Builds only the React web shell into apps/web/dist.
build:ascope
Builds only the AdvantageScope Lite assets into dist/advantagescope. Requires emscripten and the AdvantageScope submodule. Applies patches/advantagescope/ first.
build:choreo
Builds only Choreo's web frontend into dist/choreo, cloning the pinned commit from vendor/tools.json and building it inline with Vite. Requires only Bun (no Flutter, no submodule).
build:elastic
Builds only Elastic Dashboard's web assets into dist/elastic. Requires a local Flutter SDK — deliberately not part of build, since Flutter is otherwise absent from this repo's toolchain (see decision 041). Applies patches/elastic/ first.
apply:ascope-patches
Applies patches/advantagescope/*.patch to the vendored submodule without building.
apply:elastic-patches
Applies patches/elastic/*.patch to the vendored submodule without building.
check:vendor-manifest
Cross-checks vendor/tools.json against .gitmodules, THIRD_PARTY_NOTICES.md, .env.example, config.ts, and each tool's Dockerfile build sites; fails if any have drifted apart. Part of verify. See decision 043.
fetch:dist
Downloads the web shell and AdvantageScope from a CodeRunner release, builds Choreo (same as build:choreo), and fetches an optional Elastic Dashboard web build. Pass --tag vX.Y.Z (or set DEMO_RELEASE_TAG) to pin the CodeRunner release; set DEMO_RELEASE_REPO to use a fork. A missing/failed Elastic fetch only warns here — /elastic/ then serves a 503.
setup:demo
One-step demo setup: pulls the workspace image, then runs fetch:dist. Pair with demo.
clean
Deletes built output directories (apps/web/dist, dist/advantagescope, dist/choreo, and dist/elastic). Does not touch runtime data under data/.
Docs Site
Script
What it does
docs:install
Installs Docusaurus dependencies inside website/. Run once before using the docs scripts.
docs:dev
Starts the Docusaurus dev server with live reload for editing documentation.
docs:build
Builds the static docs site into website/build/.
Database
Script
What it does
migrate
Applies all pending database migrations. Called automatically by start. Run manually after pulling a new release before restarting the control plane.
migrate:status
Shows which migrations have been applied and which are pending, without making any changes.
audit:prune
Deletes audit log entries older than a given date. Usage: bun run audit:prune --before YYYY-MM-DD [--dry-run]. Use to keep the database from growing unbounded over a long season.
Docker Images and Containers
Script
What it does
docker:pull:workspace
Pulls the workspace image (${SCRIPTUM_IMAGE_NS:-ghcr.io/mathewdunne}/coderunner-workspace:${SCRIPTUM_TAG:-latest}) from the registry. Called automatically by build.
docker:build:workspace
Builds the workspace image locally from containers/code/Dockerfile, tagged with the same canonical name the pull uses — so a rebuild is picked up directly by docker compose up. Use when iterating on the container itself; normal deployments pull the prebuilt image instead.
docker:build:control
Builds the control-plane image locally: web shell, AdvantageScope Lite (compiled in-image via emsdk), and Choreo's web frontend (cloned and built in-image) all come from source; Elastic Dashboard must already be built at dist/elastic (via build:elastic or fetch:dist) before running this, since the image has no Flutter toolchain. Choreo's repo/commit pin is passed explicitly from vendor/tools.json. Normal deployments pull the published image instead.
docker:cleanup
Removes all stopped managed containers (those with the frc-sim.managed=true label). Safe to run while the control plane is up. Accepts --dry-run to preview what would be removed.
docker:rebuild-workspaces
Removes all running and stopped managed V2 workspace containers and clears their database leases, forcing fresh containers on next login. Student project files are untouched; they are bind-mounted and survive container removal. Accepts --dry-run. Run this after updating the workspace image to force students into the new image on their next session.
Users and Access
Role (admin/student) is not stored locally — it's recomputed on every
request from the signed-in member's Legion scriptum-admin group
membership. Grant or revoke admin access in Legion's own /admin/groups, not
here.
Script
What it does
users:list
Lists all users in the database with their name, username, role, and workspace slug.
migrate:legion-identity
Read-only reconciliation report matching pre-existing local user rows against the Legion roster by name, for teams migrating real production data onto Legion auth. Requires LEGION_BASE_URL and LEGION_API_KEY. Writes nothing.
Backup and Restore
Script
What it does
backup
Backs up the SQLite database and all student project and assets directories to a timestamped directory under data/backups/. Accepts --data-dir, --output, and --projects-only flags. Safe to run against a running instance.
restore
Restores a backup created by backup. Usage: bun run restore -- <backup-dir>. Accepts --workspace <id> to restore a single workspace, plus --skip-db, --skip-assets, and --dry-run. Stop the control plane before restoring to avoid conflicts.
Quality and Tests
Script
What it does
typecheck
Runs tsc --noEmit across all packages. Use to catch type errors before committing.
lint
Runs Biome linting across the codebase (read-only).
lint:fix
Runs Biome linting and applies safe auto-fixes.
format
Runs Biome formatter and writes changes.
check
Runs Biome lint and format checks together (read-only, suitable for CI).
check:fix
Runs Biome lint, format, and import organization and writes all safe fixes. Run this before finalizing any code change.
verify
Full CI gate: biome ci, typecheck, all tests, and E2E. Must pass before merging.
test
Runs Bun unit and integration tests for the control plane and shared packages. No Docker required.
test:web
Runs Vitest frontend tests for the React web shell. No Docker required.
e2e
Runs Playwright E2E tests against an in-process mocked app (~55 tests). No Docker required.
e2e:ui
Opens the Playwright UI for interactive E2E debugging.
e2e:debug
Runs E2E tests with PWDEBUG=1 for step-through debugging.