CtrlK
BlogDocsLog inGet started
Tessl Logo

setup-review-sandbox

One-time setup of the sandbox prerequisites used by the reproduce-issue skill and the reproduce-verifier agent — Docker, the isolation runtime (gVisor on Linux / Colima on macOS), healthy container networking, and the nx-review-sandbox toolchain image (built from the repo's mise.toml). Idempotent; re-run any time to verify or repair. Use when the user says "set up the review sandbox", "install the sandbox prereqs", "build the sandbox image", or a reproduce-issue preflight reports something MISSING.

72

Quality

90%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Set up the review sandbox (one-time)

Installs and verifies everything the reproduce-issue skill / reproduce-verifier agent need to run untrusted PR code in isolation. Idempotent — each step checks first and only acts if needed. Steps needing sudo are handed to the user to run in their terminal (this skill cannot sudo non-interactively).

Run uname -s first — the path differs on Linux vs macOS.

1. Docker

docker info >/dev/null 2>&1 && echo "docker OK" || echo "docker MISSING"
  • MISSING, Linux: install Docker Engine, then sudo systemctl enable --now docker and add yourself to the docker group (sudo usermod -aG docker $USER, then re-login).
  • MISSING, macOS: brew install colima docker then colima start (or install Docker Desktop).

2. Isolation runtime

Linux — gVisor (runsc)

docker info --format '{{range $k,$v := .Runtimes}}{{$k}} {{end}}' | grep -q runsc && echo "runsc OK" || echo "runsc MISSING"

If MISSING, have the user run this in their terminal (needs sudo; their shell is fish — exit codes are $status):

sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
curl -fsSL https://gvisor.dev/archive.key | sudo gpg --dearmor -o /usr/share/keyrings/gvisor-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/gvisor-archive-keyring.gpg] https://storage.googleapis.com/gvisor/releases release main" | sudo tee /etc/apt/sources.list.d/gvisor.list
sudo apt-get update && sudo apt-get install -y runsc
sudo runsc install          # registers runsc as a Docker runtime
sudo systemctl restart docker

Then re-check the runtime line above.

macOS — the Docker VM is the sandbox

No runsc. Just confirm the VM is up:

docker info >/dev/null 2>&1 && echo "docker VM OK" || echo "start it: colima start"

3. Container networking (catches the veth class of breakage)

docker run --rm --network none alpine true && echo "sandbox OK"
docker run --rm alpine true && echo "networking OK" || echo "networking BROKEN"

If the first passes but the second fails with veth ... operation not supported:

sudo modprobe veth

If modprobe errors with a BTF / version mismatch (failed to validate module [veth] BTF), the running kernel no longer matches its on-disk modules (a kernel update landed while it was booted) — reboot, after which it auto-loads. Persist it: echo veth | sudo tee /etc/modules-load.d/veth.conf.

4. The toolchain image (nx-review-sandbox)

Needed only to build an unreleased PR's nx in the sandbox (reproduce-verifier Level 2). Reproducing against a published nx version does NOT need it.

Build it — unconditionally, without first checking whether it exists:

bash tools/review-sandbox/build-image.sh

Don't gate this on an existence check. An image built from any older revision passes one identically, so a missing capability stays invisible until a review is mysteriously slow — which is exactly how an image predating the pnpm-store warming went unnoticed for two weeks, costing ~25 minutes of package downloads on every review in between. Docker's layer cache already answers the question properly: ~0.6 s when nothing changed, a real rebuild when something did. review-pr calls the same script in its own pre-flight for that reason, so the image is kept current by every review rather than by remembering to re-run this skill.

The script builds from a minimal context — five entries, ~2 MB, almost all of it the lockfile — and never . (the repo root), which would ship the whole monorepo (node_modules / .git / dist — many GB) to the daemon. All five entries are load-bearing; the Dockerfile explains what each omission breaks.

This installs the repo's exact toolchain — node/java/dotnet/maven/rust/bun via mise — and warms the pnpm store so reviews link packages instead of downloading them. Takes a while and several GB (the warm store is ~2.6 GB of that). Requires steps 1 + 3 to pass first (build needs working networking).

Note that the store is warm but read-only, living in an image layer: the first review in a container has to copy the part its lockfile touches up into the writable layer (~2.3 GB, minutes) before it can hardlink to it. That is why reviews share one host container per image — the copy-up is then paid once rather than once per PR, and a second review's install measures ~0.39 GB and ~12 s.

5. Verify (smoke test)

Confirm the sandbox actually isolates and carries the tools:

# RUNTIME="--runtime=runsc"  on Linux, ""  on macOS
docker run --rm $RUNTIME nx-review-sandbox:latest bash -c '
  cd /work    # mise resolves versions from the mise.toml here; do NOT use bash -l (a login shell resets PATH, dropping the mise dirs)
  echo "kernel: $(uname -r)"       # Linux+gVisor: 4.19.0-gvisor ; macOS: the VM kernel
  mise ls | head
  node --version; java --version 2>&1 | head -1; dotnet --version
'

Green when: the kernel is NOT your host kernel, and node/java/dotnet report versions. Report a concise ✅/❌ per step and what (if anything) the user still needs to run.

6. Reclaiming the disk

Reviews clean up after themselves (sandbox stop deletes the review's /work/<id> subtree), and sandbox prune sweeps subtrees whose registry row is gone. What neither touches is the shared state, because that state is the cache:

.claude/tools/sandbox prune --store   # pnpm store prune + git gc in the shared repo
.claude/tools/sandbox prune --host    # destroy the shared host; next start rebuilds it cold

Both refuse while any sandbox row is live — they would be deleting files a running review is reading. After an image rebuild you do not need --host to pick the new toolchain up: the host is named after the image's resolved id, so the next start builds a fresh one on its own. --host is how you reclaim the superseded host's several GB, and the mitigation worth knowing about: reviews share a pnpm store, so a malicious PR could in principle poison it for a later review. That stays inside the container and cannot reach the host, but it can corrupt a later review's findings.

Repository
nrwl/nx
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.