python -m kit doctor checks this machine for what villa's First Letters workflow needs (a 12 GB GPU, 16 GB of memory, 25 GB of disk, git, uv and docker, villa and VC3D's tools), names AMD and Intel GPUs, and prints pass, warn or fail for each.
| Field | Value |
|---|---|
| Id | doctor |
| Status | Current |
| Kind | kit command, kit module |
| Area | Planning and prizes |
| Run | python -m kit doctor, from kit import doctor |
| Code | kit/doctor.py, kit/cli.py (cmd_doctor) |
| Tests | tests/test_kit.py, tests/test_qol_tools.py, tests/test_doctor_gpus.py |
| Needs | Python 3.10 or newer, standard library only. Uses nvidia-smi (from the NVIDIA driver) or rocm-smi (from ROCm) when it is on PATH, imports torch when it is installed and no NVIDIA GPU was found (not on Apple Silicon), and reads the environment variables VILLA, VC_BIN, HOME, VC3D_CONFIG_DIR, RUNPOD_POD_ID and RUNPOD_VOLUME_ID |
| Runs on | Any machine. 0.34 to 0.43 s per call with no nvidia-smi installed (5 runs, measured 2026-10-16, 4-core Xeon cloud container). With nvidia-smi, add its run time, at most 20 s (the timeout) |
| Network | None |
| Writes | A 64 MB test file under --disk (and with --remote, under the cache folder's nearest existing parent), deleted after the speed test; --no-speed writes nothing. It runs nvidia-smi --query-gpu=name,memory.total --format=csv,noheader,nounits and rocm-smi --showproductname --showmeminfo vram --json when those programs are on PATH |
| Go-ahead | Not needed |
| Released | Public main since 2026-10-06 (2daee8e), with the Apple Silicon path since 2026-10-07 (e8f3dda). Also inside the AutoPipeline release copy at faada83, and as scrolls-workbench doctor in the installable package since 2026-10-14 (2582ab7) |
| Guide | mac.md (what runs on an Apple Silicon Mac), compute.md (hardware that has worked, and the thresholds' sources) |
| Checked | 2026-10-24 against commit cc03099 |
villa's First Letters workflow, the official ink detection tutorial (scrollprize.org/tutorial5) that plan prints, needs several things on the machine: an NVIDIA GPU with CUDA for ink inference, room on disk for surface volumes, uv to run villa's Python, VC3D's command-line tools (vc_grow_seg_from_seed to grow a surface, vc_render_tifxyz to render it), and a villa checkout. kit doctor checks six of these and prints one line each, pass, warn or fail, then an overall verdict that is the worst of the six.
The thresholds come from published runs, as the module's docstring records: 12 GB of GPU memory, because Bullo27's first-letters-survey ran on an RTX 3060 12 GB and a July 2026 progress prize made the spiral fitter run on 12 GB cards; and 25 GB of free disk, because one tutorial segment of the ink-labels dataset is about 25 GB (tutorial5). The 16 GB memory threshold (MIN_RAM_GB) has no source in the code. "GB" in its messages means GiB (1,024^3 bytes).
On an Apple Silicon Mac (macOS on arm64) the GPU check is a warning, not a failure: there is no CUDA, but VC3D, rendering and lasagna (villa's flattening tool, --device mps) run locally (mac.md). There it also finds VC3D's tools inside /Applications/VC3D.app/Contents/MacOS when VC_BIN is not set.
It does not run anything on the GPU, check the CUDA driver or PyTorch, test MPS (Metal Performance Shaders, PyTorch's Apple GPU backend), check the villa checkout's commit or whether uv sync ran, or check access to the open-data bucket or to Modal. A pass says the parts are there, not that the pipeline runs: running the w035 control (step 1 of plan) is that test. Its report makes no claim about any scroll.
GPUs other than NVIDIA. When nvidia-smi finds nothing and the machine is not an Apple Silicon Mac, it asks rocm-smi --showproductname --showmeminfo vram --json for AMD cards (the keys Card Series and VRAM Total Memory (B) per cardN, as ROCm's rocm_smi.py writes them, read 24 Oct 2026), then imports torch: a ROCm build (torch.version.hip set) lists AMD cards through torch.cuda, and torch.xpu lists Intel GPUs. Either reports as warn, never pass, because villa's spiral fitting asks for "an NVIDIA GPU" (tutorial_spiral, read 24 Oct 2026) and other villa steps are not tested on them here. /dev/kfd or /opt/rocm with no card listed warns too, since that usually means a driver or group-permission problem rather than no card. Before this, an AMD machine got fail with "No NVIDIA GPU found".
--remote, for a rented or cloud machine. VC3D keeps every chunk it streams from a remote volume in a cache folder, so on a pod or job where the home folder sits on a small or slow disk the cache, not the volume, fills the disk. --remote adds a cache line: the folder VC3D will use, found in VC3D's own order (villa main RemoteCacheSettings.cpp and GlobalCacheRoot.hpp, read 24 Oct 2026: cache.json in $VC3D_CONFIG_DIR or ~/.VC3D, then remote_cache_dir under [viewer] in VC3D.ini there, then /volpkgs/remote_cache or /ephemeral/remote_cache when that mount exists, then ~/.VC3D/remote_cache), and the free space there. With the speed test on, a cacheio line times that disk when it differs from --disk. On RunPod (RUNPOD_POD_ID set, RunPod's variables) the line says whether the folder survives, quoting RunPod's storage page (read 24 Oct 2026): the container disk "is cleared when the Pod stops"; the volume disk at /workspace "survives Pod stops and restarts, but is deleted when the Pod is terminated"; a network volume (RUNPOD_VOLUME_ID set) replaces it at /workspace. Hugging Face Jobs set no variable we could find documented, so there it reports only the folder and its space.
In this repository GPU work goes to Modal (the Modal rule, hard rule 11), so a fail on gpu on a laptop or in a Claude cloud session is expected. It means the GPU steps go into a Modal run spec, not that the machine is broken. "Rent a GPU" in its messages means that here.
- At the start of a session: the scroll-session skill runs it after prizes.
- On a new machine, or after installing villa, VC3D or uv, to see what is still missing.
- Before running the w035 control locally (step 1 of plan, or mac-verify on a Mac).
- To see whether a GPU has the 12 GB the published runs used.
Do not use it:
- To show that ink inference runs: run the control (step 1 of plan; on a Mac,
bash scripts/mac-verify.sh, see mac-verify). - To check that two devices give the same map (CPU against MPS): use verify, with its control.
- To price a job: use
kit cost(plan) or the Modal calculator (cloudcost); for the time and electricity of a local run, run-local. - To test whether Modal is reachable: a Claude cloud session needs
pip install 'modal[api-proxy-support]', Chase's sign-in and an allow rule, thenmodal app listanswers (the Modal rule); without them, write a run spec indocs/compute/modal-specs/instead.
python -m kit doctor
VILLA=VILLA_DIR VC_BIN=VC_BIN_DIR python -m kit doctor --disk WORK_DIR
python -m kit doctor --remote # on a RunPod pod, a Hugging Face Job or any cloud machineVILLA_DIR: your villa checkout (the folder holdingvesuvius/andvolume-cartographer/).VC_BIN_DIR: the folder holdingvc_grow_seg_from_seedandvc_render_tifxyz; on a Mac with VC3D.app installed, leaveVC_BINunset.WORK_DIR: the folder where volumes and renders will go; its file system's free space is checked.
In the cloud container where this page was written (no GPU, VILLA and VC_BIN unset, 2026-10-16) it printed, with exit code 1:
[fail] gpu No NVIDIA GPU found (nvidia-smi absent or failed). Ink inference needs CUDA; see docs/compute.md for rentals.
[pass] memory 16 GB memory
[pass] disk 26 GB free at . (one tutorial segment is about 25 GB)
[pass] tools git, uv and docker on PATH
[warn] villa VILLA not set. Clone https://github.com/ScrollPrize/villa and export VILLA=/path/to/villa
[warn] vc_bin VC_BIN not set. Needed for vc_grow_seg_from_seed and vc_render_tifxyz built from villa main
overall: fail
With a stand-in nvidia-smi that reported an RTX 3060 (12,288 MiB) and an A10 (23,028 MiB), a folder holding empty vesuvius/ and volume-cartographer/, and a VC_BIN folder holding only vc_render_tifxyz, it printed overall: warn and exit code 0:
[pass] gpu NVIDIA GeForce RTX 3060 12 GB; NVIDIA A10 22 GB
...
[pass] villa villa checkout at /tmp/claude-docs-public-doctor/villa
[warn] vc_bin /tmp/claude-docs-public-doctor/vcbin lacks vc_grow_seg_from_seed
Since 24 October the no-GPU line reads [fail] gpu No GPU found (nvidia-smi, rocm-smi and torch found none). Ink inference needs CUDA; see docs/compute.md for rentals. With --remote --no-speed in the same kind of container (24 Oct 2026, no torch installed) it added:
[pass] cache VC3D caches remote chunks in /root/.VC3D/remote_cache (VC3D's default); 28 GB free there
and with RUNPOD_POD_ID set, the same line ended RunPod: outside /workspace, on the container disk, which "is cleared when the Pod stops"; set remote_cache_dir in VC3D.ini to a folder under /workspace to keep the cache (https://docs.runpod.io/pods/storage/types). With the speed test on it also printed [pass] cacheio /root: write 469 MB/s, read 3007 MB/s. No AMD or Intel card was available to run it on; those paths are tested with stand-ins only (Tests).
It worked when the last line is overall: pass, overall: warn or overall: fail. Read each warn and fail line; each says what is missing.
- Every check can fail, and the tests show it (
DoctorTest): no GPU givesfail, an 8 GB cardwarnand a 12 GB cardpass; a folder withoutvesuvius/andvolume-cartographer/givesfailand one with thempass; 15.6 GB of memory passes and 8 GB warns. - Run against stand-ins on 2026-10-16 (synthetic inputs, this container): an
nvidia-smireporting a GTX 1080 (8,192 MiB) gave[warn] gpu ... Below 12 GB, one that exited with code 9 gave[fail] gpu, aVILLAfolder without the two subfolders gave[fail] villaand exit code 1, and aPATHwithout uv gave[warn] tools missing: uv. - The non-NVIDIA paths can fail and are never a pass (
tests/test_doctor_gpus.py): rocm-smi JSON for two cards parses to their names and MiB; an AMD card warns (and says when torch is not a ROCm build or the card is under 12 GB), an Intel card warns, ROCm with no card warns, nothing at all fails, and an NVIDIA card still passes. The cache folder follows VC3D's order in every branch; acache.jsonVC3D would refuse (wrong version, relative root, not JSON) fails; under 25 GB warns; each RunPod storage case gives its own quoted sentence. - A real failure on record: in the cloud session that built this repository on 2026-10-06 it printed
[fail] gpu No NVIDIA GPU found(error log). - What a pass does not show: that CUDA, PyTorch or villa's inference work. The control run (w035, step 1 of plan) shows that; it in turn shows only that the pipeline runs, since w035 is a training segment (log).
Claim label: None for the report, which describes this machine and makes no claim about scrolls. Its 12 GB GPU and 25 GB disk thresholds are Sourced facts (Bullo27's first-letters-survey on an RTX 3060 12 GB; scrollprize.org/tutorial5).
usage: python -m kit doctor [-h] [--disk DISK] [--no-speed] [--remote]
| Option | Default | Meaning |
|---|---|---|
--disk DISK |
. |
Path whose file system's free space is checked: the current folder by default. Point it at where volumes, renders and VC3D's cache will go. Also where the disk speed test writes its 64 MB file. A path that does not exist stops with a FileNotFoundError traceback and exit code 1 |
--no-speed |
off | Skip the 64 MB disk speed test (the speed and cacheio lines) |
--remote |
off | On a rented or cloud machine: also check where VC3D will cache streamed chunks (cache), its speed (cacheio, with the speed test, when it is on another folder than --disk), and on RunPod whether it survives a stop |
| Variable | Default | Meaning |
|---|---|---|
VILLA |
unset, which gives warn |
Path of a villa checkout. pass when it holds both vesuvius/ and volume-cartographer/ folders, fail otherwise. An empty value is read as the current folder |
VC_BIN |
unset, which gives warn; on Apple Silicon, /Applications/VC3D.app/Contents/MacOS when that folder exists |
Folder of VC3D's command-line tools. pass when both vc_grow_seg_from_seed and vc_render_tifxyz are in it, warn otherwise. Never fail |
PATH |
the shell's | Searched for nvidia-smi, rocm-smi, git, uv and docker (shutil.which) |
HOME, VC3D_CONFIG_DIR |
the user's home; unset | With --remote: where VC3D's cache.json and VC3D.ini are looked for (VC3D_CONFIG_DIR, else HOME/.VC3D) |
RUNPOD_POD_ID, RUNPOD_VOLUME_ID |
unset | With --remote: set by RunPod on a pod and when a network volume is attached; they choose the RunPod sentence on the cache line |
from kit import doctor
results = doctor.run_checks(disk_path="/data") # [(name, status, detail), ...]
text, worst = doctor.format_report(results)| Function | Returns | Raises | Notes |
|---|---|---|---|
is_apple_silicon(system=None, machine=None) |
bool | Nothing | True only for Darwin on arm64; the defaults come from platform.system() and platform.machine() |
ram_gb() |
float (GiB of physical memory), or None |
Nothing | From os.sysconf; None where that is missing, such as on Windows |
gpus(run=subprocess.run) |
list of (name, memory_mb) |
Nothing | Runs nvidia-smi with a 20 s timeout; [] when it is not on PATH, exits non-zero or times out. run is replaceable for tests |
parse_nvidia_smi(text) |
list of (name, memory_mb) with int MiB |
Nothing | Splits each line at its last comma; lines whose last field is not a number are skipped |
check_gpu(found, apple_silicon=False, amd=(), xpu=(), hip=None, rocm=False) |
(status, detail) |
Nothing | With NVIDIA cards in found: pass when the largest has at least MIN_GPU_MB (12,288 MiB), warn below. Without: warn for AMD cards in amd (naming hip, the ROCm version of torch, or saying torch is not a ROCm build), for Intel cards in xpu, for rocm (ROCm installed, no card listed), and on Apple Silicon; fail otherwise |
parse_rocm_smi(text) |
list of (name, memory_mb) |
Nothing | From rocm-smi --showproductname --showmeminfo vram --json: cardN entries, name from Card Series (else Device Name, Card Model), memory from VRAM Total Memory (B) (0 when absent); [] for text that is not JSON |
amd_gpus(run=subprocess.run, which=shutil.which) |
list of (name, memory_mb) |
Nothing | Runs rocm-smi (20 s timeout) when which finds it; [] when absent or failing |
torch_gpus() |
{"hip", "amd", "xpu"} |
Nothing | Imports torch; hip is torch.version.hip; amd lists torch.cuda devices only on a ROCm build; xpu lists torch.xpu devices. All empty without torch or on a driver error |
rocm_present(exists=os.path.exists) |
bool | Nothing | /dev/kfd or /opt/rocm exists |
vc3d_cache_root(env=None, exists=os.path.exists, read=...) |
(Path, how) |
ValueError for a cache.json that is not JSON, not version 1, or has a relative root |
VC3D's order, in What it does; how says which rule chose the folder |
check_cache(env=None, exists=os.path.exists, disk_usage=shutil.disk_usage, read=None) |
(status, detail) |
Nothing | fail for a cache.json VC3D refuses, pass at 25 GiB free in the folder's nearest existing parent, warn below; adds the RunPod sentence when RUNPOD_POD_ID is set |
check_disk(path) |
(status, detail) |
FileNotFoundError (or another OSError) for a path that does not exist or cannot be read |
pass at 25 GiB free (MIN_DISK_GB) or more, warn below; never fail |
check_ram(gb, apple_silicon=False) |
(status, detail) |
Nothing | pass when round(gb) is at least 16 (MIN_RAM_GB), so a "16 GB" machine that reports 15.6 GiB passes; warn below or for None |
check_tools(which=shutil.which) |
(status, detail) |
Nothing | pass when git, uv and docker (TOOLS) are all found, warn listing the missing ones |
check_villa(path) |
(status, detail) |
Nothing | warn for None, pass for a folder with both subfolders, fail otherwise |
check_vc_bin(path, apple_silicon=False) |
(status, detail) |
Nothing | pass or warn, never fail; on Apple Silicon a None path falls back to MAC_VC_BIN when that folder exists |
sysctl(name, run=subprocess.run) |
str or None | Nothing | sysctl -n NAME on macOS (5 s timeout); None when it fails or is absent |
check_rosetta(system=None, machine=None, read=sysctl, torch_info=None) |
None off macOS, else (status, detail) |
Nothing | fail when this Python is an Intel build under Rosetta on an Apple Silicon Mac (sysctl.proc_translated is 1, or platform.machine() is not arm64 while hw.optional.arm64 is 1); warn when torch is installed but has no usable MPS; pass otherwise |
cpu_quota(root='/sys/fs/cgroup', proc='/proc/self/cgroup') |
float CPUs, or None when unlimited or unknown | Nothing | The smallest quota from this process's own cgroup up to the root: cgroup v2 cpu.max, or v1 cpu.cfs_quota_us over cpu.cfs_period_us |
check_threads(visible=None, quota=None, env=None) |
(status, detail) |
Nothing | warn when the quota is under 0.9 of the CPUs Python sees and NUMBA_NUM_THREADS, OMP_NUM_THREADS, MKL_NUM_THREADS and OPENBLAS_NUM_THREADS (THREAD_VARS) are not all set at or below it; the detail gives the export line |
check_disk_speed(path, nbytes=SPEED_BYTES, clock=time.perf_counter) |
(status, detail) |
Nothing | Writes and syncs a temporary file of SPEED_BYTES (64 MiB), drops it from the page cache (posix_fadvise on Linux, F_NOCACHE on macOS), reads it back and deletes it; warn under MIN_READ_MBS (200 MB/s) or when the file cannot be written |
run_checks(env=None, disk_path='.', speed=True, remote=False) |
list of (name, status, detail): rosetta (macOS only), threads (Linux only), speed (unless speed=False), cache and cacheio (with remote=True), then gpu, memory, disk, tools, villa, vc_bin, in that order |
As check_disk |
env (default os.environ) supplies VILLA, VC_BIN and the --remote variables; the GPU, memory, platform and PATH are always this machine's |
format_report(results) |
(text, worst), worst one of pass, warn, fail |
Nothing | The text the command prints, ending in overall: WORST |
Module constants: SPEED_BYTES = 64 << 20, MIN_READ_MBS = 200, THREAD_VARS, MIN_GPU_MB = 12 * 1024, MIN_DISK_GB = 25, MIN_RAM_GB = 16, TOOLS = ("git", "uv", "docker"), MAC_VC_BIN = Path("/Applications/VC3D.app/Contents/MacOS"), and the status words PASS, WARN, FAIL ("pass", "warn", "fail").
| Input | Where it comes from | Notes |
|---|---|---|
| GPUs | nvidia-smi --query-gpu=name,memory.total --format=csv,noheader,nounits |
One line per card, NAME, MEMORY_MIB |
| AMD and Intel GPUs | rocm-smi --showproductname --showmeminfo vram --json; torch (torch.version.hip, torch.cuda, torch.xpu) |
Only when no NVIDIA GPU was found and not on Apple Silicon |
| VC3D's cache folder | cache.json and VC3D.ini in $VC3D_CONFIG_DIR or ~/.VC3D; /volpkgs, /ephemeral |
With --remote |
| Physical memory | os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES") |
Not available on Windows |
| Free disk | shutil.disk_usage(--disk) |
The free space of the file system that holds the path |
| Tools | shutil.which on PATH |
git, uv, docker |
| villa and VC3D paths | VILLA, VC_BIN |
See Environment variables |
| Platform | platform.system(), platform.machine() |
Apple Silicon is Darwin on arm64 |
Text on stdout, one line per check, [STATUS] NAME DETAIL (status right-aligned in 4 characters, name left-aligned in 7), then a blank line and overall: STATUS. There is no JSON form; in Python, run_checks() gives the same as tuples.
| Check | pass when |
warn when |
fail when |
|---|---|---|---|
rosetta (macOS only) |
Python is arm64 (and torch, when installed, sees the MPS GPU), or an Intel Mac | arm64 Python whose torch lacks MPS, or MPS not available | An Intel-build Python running under Rosetta on Apple Silicon |
threads (Linux only) |
No CPU quota below the CPUs Python sees, or the four thread variables already set to fit it | A smaller quota without matching thread variables | Never |
speed |
Read back at 200 MB/s or more | Slower, or the test file could not be written | Never |
cache (--remote) |
25 GiB or more free where VC3D will cache chunks | Less | A cache.json VC3D would refuse |
cacheio (--remote, speed test on) |
As speed, on the cache folder's disk |
As speed |
Never |
gpu |
The largest NVIDIA card has 12,288 MiB or more | An NVIDIA card below 12 GB; an AMD or Intel GPU; ROCm with no card listed; or no GPU on Apple Silicon | No GPU found, not on Apple Silicon |
memory |
16 GB or more after rounding | Less, or unreadable | Never |
disk |
25 GiB or more free at --disk |
Less | Never |
tools |
git, uv and docker on PATH |
Any missing | Never |
villa |
VILLA holds vesuvius/ and volume-cartographer/ |
VILLA not set |
VILLA set to anything else |
vc_bin |
Both VC3D tools in VC_BIN (or in VC3D.app on Apple Silicon) |
Not set, or a tool missing | Never |
GPU sizes are printed as whole GB rounded down (23,028 MiB prints as 22 GB), and free disk and memory are rounded to whole GB, so a disk line can read 25 GB free and still warn when the free space is just under 25 GiB.
| Exit code | Meaning |
|---|---|
0 |
No check failed: overall: pass or overall: warn |
1 |
At least one check failed (overall: fail), or a Python error with a traceback and no overall: line, such as a --disk path that does not exist |
2 |
A usage error from the argument parser |
| What you see | Why | What to do |
|---|---|---|
usage: ... then error: ... on stderr, exit code 2 |
A missing or wrong argument | Check the command against Commands and options |
[fail] gpu No GPU found (nvidia-smi, rocm-smi and torch found none). Ink inference needs CUDA; see docs/compute.md for rentals. (before 24 Oct 2026: No NVIDIA GPU found (nvidia-smi absent or failed)...) |
nvidia-smi is not on PATH, exited non-zero, took over 20 s, or printed nothing it could read, and neither rocm-smi nor torch listed another GPU |
Expected on a laptop or a cloud session: GPU steps go to Modal through a run spec (the Modal rule). On a GPU machine, install the NVIDIA driver and run nvidia-smi by hand |
[warn] gpu AMD GPU (ROCm): NAME N GB. ... villa's spiral fitting asks for an NVIDIA GPU (scrollprize.org/tutorial_spiral); other villa steps are not tested on it here |
An AMD card, found by rocm-smi or a ROCm build of torch | Expect to test each villa step; ScrollFiesta has a HIP backend (tracing tools). For spiral fitting, rent an NVIDIA GPU |
... this Python's torch is not a ROCm build: install one from https://pytorch.org inside the AMD line |
rocm-smi lists the card but this torch was built for CUDA or CPU | Install the ROCm wheel that pytorch.org lists for your ROCm version |
[warn] gpu Intel GPU (torch.xpu): NAME N GB. villa's spiral fitting asks for an NVIDIA GPU ... |
torch sees an Intel GPU | As for AMD |
[warn] gpu ROCm is installed (/dev/kfd or /opt/rocm) but neither rocm-smi nor torch listed an AMD GPU: check the driver with rocm-smi, and that this user is in the video and render groups |
ROCm is present but no card was listed | Run rocm-smi by hand; add the user to the video and render groups |
[fail] cache PATH/cache.json does not read as JSON: ERROR or [fail] cache PATH/cache.json needs version 1 and an absolute root; VC3D refuses it otherwise |
With --remote: a cache.json VC3D itself would refuse |
Fix or remove that file |
[warn] cache VC3D caches remote chunks in PATH (HOW); N GB free there. Under 25 GB: a long trace can fill it |
With --remote: little space where VC3D caches |
Set remote_cache_dir under [viewer] in VC3D.ini to a bigger disk |
RunPod: outside /workspace, on the container disk, which "is cleared when the Pod stops"; ... at the end of the cache line |
With --remote on RunPod: the cache will be lost at the next stop |
Set remote_cache_dir to a folder under /workspace if you want it kept |
[warn] gpu NAME N GB. Below 12 GB: use batch size 1 or rent a GPU. |
The largest card has under 12,288 MiB | Use --batch 1 in plan, or run the GPU steps on Modal |
[warn] gpu Apple Silicon, no CUDA. Runs locally: VC3D app, rendering, lasagna (--device mps). Stock villa ink inference uses the CPU; open PRs #1865/#1812 add MPS. Full segments: rent a GPU. See docs/mac.md |
A Mac with Apple Silicon. The PR statuses in this text date from 2026-10-07 | Follow mac.md and python -m kit plan SCROLL --mac; full segments go to Modal |
[warn] memory could not read installed memory |
os.sysconf is missing (Windows) or failed |
Check memory by hand |
[warn] memory N GB memory |
Under 16 GB after rounding | Small renders only; heavy CPU work goes to Modal |
[warn] disk N GB free at PATH (one tutorial segment is about 25 GB) |
Under 25 GiB free on that file system | Free space, or point --disk and your work folder at a bigger disk |
[fail] rosetta this Python is an Intel build running under Rosetta: no MPS GPU and slow NumPy. Install an arm64 Python ... |
On an Apple Silicon Mac, this Python (often an old Anaconda or an Intel Homebrew in /usr/local) is an x86_64 build | Install an arm64 Python, make a new venv with it, reinstall packages; check python3 -c 'import platform; print(platform.machine())' prints arm64 |
[warn] rosetta arm64 Python, but this torch has no MPS support: pip install --upgrade torch |
An old or CPU-only torch wheel | Upgrade torch in the venv |
[warn] rosetta arm64 Python, torch has MPS but it is not available (macOS 12.3 or newer is needed) |
macOS older than 12.3, or a broken torch install | Update macOS, or reinstall torch |
[warn] threads N CPUs visible but the CPU quota is Q: Numba, OpenMP and torch start N threads and wait on the quota. Before running: export ... |
A container whose CPU quota is smaller than the machine's CPUs (Docker --cpus, RunPod, a cloud job) |
Paste the export line before the run, and call torch.set_num_threads as printed |
[warn] speed PATH: write W MB/s, read R MB/s. Under 200 MB/s: keep volume chunk caches on a local SSD ... |
--disk is on a network, overlay or synced file system |
Point caches and work folders at a local disk, or pass --disk there |
[warn] speed could not write a test file under PATH: ERROR or disk speed test under PATH failed: ERROR |
--disk is read-only or full |
Point --disk at a writable folder, or pass --no-speed |
... (read may come from memory: this system cannot drop the file from its cache) at the end of the speed line |
The system has neither posix_fadvise nor F_NOCACHE (Windows), so the read speed can be the page cache's |
Treat the read number as an upper bound |
FileNotFoundError: [Errno 2] No such file or directory: 'PATH' and a traceback, exit code 1 |
--disk names a path that does not exist |
Create the folder first, or pass an existing one |
[warn] tools missing: NAMES (uv runs villa; docker runs the VC3D image) |
git, uv or docker is not on PATH |
Install the missing tool; docker matters only for the VC3D container, which villa issue #1588 reported stale |
[warn] villa VILLA not set. Clone https://github.com/ScrollPrize/villa and export VILLA=/path/to/villa |
VILLA is not set |
Clone villa and export VILLA |
[fail] villa PATH does not look like a villa checkout (no vesuvius/ and volume-cartographer/) |
VILLA points at a folder without those two subfolders (an empty VILLA means the current folder) |
Point VILLA at the top of the villa clone |
[warn] vc_bin VC3D.app not in /Applications. Install the macos-arm64 .dmg from https://github.com/ScrollPrize/villa/releases |
Apple Silicon, VC_BIN not set and no VC3D.app |
Install VC3D.app, or set VC_BIN |
[warn] vc_bin VC_BIN not set. Needed for vc_grow_seg_from_seed and vc_render_tifxyz built from villa main |
VC_BIN is not set (not on Apple Silicon) |
Build VC3D from villa main and export VC_BIN |
[warn] vc_bin PATH lacks vc_grow_seg_from_seed, vc_render_tifxyz |
One or both tools are not in VC_BIN (or the folder does not exist) |
Point VC_BIN at the folder that holds them |
run_checksdecides whether this is Apple Silicon (platform.system() == "Darwin"andplatform.machine() == "arm64").gpu:gpus()runsnvidia-smiifshutil.whichfinds it (20 s timeout,check=True), andparse_nvidia_smireadsNAME, MEMORY_MIBlines.check_gpucompares the largest card withMIN_GPU_MB = 12 * 1024.memory: physical pages times page size, in GiB;round(gb) >= MIN_RAM_GB(16) passes, because a machine sold as 16 GB reports slightly less.disk:shutil.disk_usage(--disk).freein GiB againstMIN_DISK_GB(25).tools:shutil.whichfor each name inTOOLS.villaandvc_bin: folder tests onVILLAandVC_BIN, with the VC3D.app fallback on Apple Silicon.rosetta(macOS),threads(Linux) andspeedrun first:sysctlfor Rosetta,/proc/self/cgroupand the cgroup files for the quota, and a 64 MiB write,fsync, cache drop and read for the disk.format_reportwrites the lines and takes the worst status (failoverwarnoverpass);cmd_doctorprints it and returns 1 when the worst isfail, 0 otherwise.
With the disk speed test: 0.29 to 0.52 s per call (3 runs, --disk /tmp, measured 2026-10-23, 4-core Xeon cloud container, which read the test file back at 2,888 MB/s); --no-speed 0.14 s. The test writes 64 MiB and deletes it. Measured 2026-10-16 in a 4-core Xeon cloud container with no nvidia-smi: 0.34 to 0.43 s per call over 5 runs, almost all Python start-up and the import of kit.cli. On a machine with nvidia-smi, add that program's run time; the call gives up after 20 s. It rents nothing and runs anywhere.
- Command:
python -m kit doctor --disk WORK_DIR. There is no JSON form; in Python,from kit import doctor; doctor.run_checks(disk_path="WORK_DIR")returns(name, status, detail)tuples. - Parse: each line
[STATUS] NAME DETAIL(STATUS ispass,warnorfail; NAME isrosetta,threads,speed,cache,cacheio,gpu,memory,disk,tools,villaorvc_bin) and the last lineoverall: STATUS. - Rerun: Safe; it only reads the machine's state.
- Success: Exit code 0 with
overall: passoroverall: warn. Exit code 1 with anoverall: failline is a finished report; exit code 1 without that line is a crash (see Failure modes). - Not a pass:
overall: passdoes not mean CUDA, PyTorch or villa's inference work; only the control run shows that. Agpupass says nothing about whether the card is free or the driver matches villa's PyTorch. - Go-ahead: Nothing for the check. Renting the GPU its messages suggest needs Chase's budget decision (the go-ahead rule, hard rule 8).
- Never: Try to sign in to Modal from a Claude cloud session because
gpufailed (the Modal rule, hard rule 11): write a run spec instead; run hours of GPU work on a laptop CPU because the other checks passed.
python -m unittest tests.test_kit.DoctorTest tests.test_qol_tools.TestDoctor tests.test_doctor_gpus -vtests/test_doctor_gpus.py covers rocm-smi parsing and its absent or failing runs, the AMD, Intel and ROCm-without-card warnings and the no-GPU failure, VC3D's cache folder order (default, /ephemeral, /volpkgs, VC3D.ini with a comment and quotes, cache.json under VC3D_CONFIG_DIR), the refused cache.json cases, low space, the three RunPod storage cases, and that --remote adds the cache line. No real AMD or Intel card was tested.
tests/test_qol_tools.py (TestDoctor) covers the Rosetta check (off macOS, a translated Intel build, arm64 with and without MPS, an Intel Mac), the thread warning and its export line, the CPU quota read from a fake cgroup tree (a v1 quota under the process's own cgroup, an unlimited and a limited v2 cpu.max), and the speed check on a real temporary file (it leaves nothing behind; a fake slow clock warns). Six older tests cover nvidia-smi parsing, the 12 GB threshold (fail, warn, pass), Apple Silicon reported as a warning that points to docs/mac.md, the memory rounding (15.6 passes, 8 warns, unreadable warns, "shared with the GPU" on a Mac), villa checkout detection, and the overall verdict. They do not cover check_disk, check_tools, check_vc_bin, run_checks, the command line or its exit codes, or a real nvidia-smi.
- 2026-10-24: AMD (rocm-smi, ROCm torch) and Intel (torch.xpu) GPUs reported as warnings instead of "No NVIDIA GPU found", a warning for ROCm with no card listed, and
--remotewith thecacheandcacheiolines (0da03d1). - 2026-10-23: three checks for silent slowdowns:
rosetta(an Intel Python on an Apple Silicon Mac),threads(a container CPU quota smaller than the CPUs Python sees) andspeed(a 64 MB disk read test), with--no-speed(3376687). - 2026-10-14:
scrolls-workbench doctorin the installable package (2582ab7, PR #58). - 2026-10-07: the Apple Silicon path: on a Mac the GPU check warns instead of failing, a memory check (16 GB) is added, and VC3D's tools are found inside VC3D.app (
e8f3dda, PR #1). - 2026-10-06: first version: the NVIDIA GPU (12 GB), free disk (25 GB), git, uv and docker,
VILLAandVC_BINchecks (2daee8e).
- mac.md: what runs on an Apple Silicon Mac, and the open villa PRs for MPS inference.
- compute.md: hardware that has run the workflow, and costs from published runs.
- tracing tools: which tracing tools run on a Mac, an AMD GPU or a CPU.
- plan: the run plan whose steps these checks prepare for, and
kit cost. - prizes: the other first command of a session.
- mac-verify: runs the w035 control on a Mac in one command.
- scroll-session: the session skill that runs this check.
- error log: the first recorded
failon the setup session's machine.