No description
  • Dockerfile 76.2%
  • Shell 23.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Gideon 3e5963887f
All checks were successful
Build and push Docker image / build-amd64 (push) Successful in 2m38s
Build and push Docker image / build-arm64 (push) Successful in 12m24s
Build and push Docker image / merge-manifest (push) Successful in 12s
Dockerfile: add Node.js 22 (mesh/DXF export builders run in Node)
2026-10-08 17:00:57 +11:00
.forgejo/workflows workflow: add arm64 job + multi-arch manifest merge (Pi5 runner) 2026-10-08 16:30:32 +11:00
examples cad-runtime: warm shared text-to-cad/cadgen container (Debian12, amd64) 2026-10-08 15:55:10 +11:00
cad.sh cad-runtime: warm shared text-to-cad/cadgen container (Debian12, amd64) 2026-10-08 15:55:10 +11:00
Dockerfile Dockerfile: add Node.js 22 (mesh/DXF export builders run in Node) 2026-10-08 17:00:57 +11:00
README.md docs: multi-arch CI + Pi5 disk warning (unblock arm64) 2026-10-08 16:37:33 +11:00

cad-runtime

A warm, shared container for text-to-cad / cadgen — the local CAD runtime (build123d + OpenCASCADE) that agent skills such as $cad, $dxf, $gcode and friends drive to generate STEP / STL / 3MF / GLB models.

Multiple agents (or several machines) can share one container instance: it runs the CAD Viewer on a stable port and builds against any project directory you mount. All the heavy per-machine pieces — Python 3.13, the OpenCASCADE kernel, libGL, headless Chromium — are pre-installed, so first use is instant.

Pull

docker pull nidavellir.jriyuu.io/jriyuu-labs/cad-runtime:latest

Tags: latest and per-commit <sha>.

Run

As a shared viewer (the default)

docker run -d --name cad-runtime \
  -p 3245:3245 \
  -v /path/to/your/cad-projects:/work \
  -v cadgen-cache:/root/.cache/cadgen \
  nidavellir.jriyuu.io/jriyuu-labs/cad-runtime:latest

Then open http://<host>:3245/?file=/work/STEP/part.step in a browser. The viewer is one long-running server for every file on the container.

The cadgen-cache volume is what makes builds fast and shareable: it holds the content-addressed geometry store. Keep it.

Build a model from its Python source

docker run --rm -v /path/to/project:/work -w /work \
  nidavellir.jriyuu.io/jriyuu-labs/cad-runtime:latest \
  cad python src/plate.py

cad is a wrapper around the pinned runtime (uvx --no-config --managed-python --python 3.13 --from cadgen==0.7.17). Two doors:

Command What it runs
cad python <model>.py the pinned python — builds a model script
cad <cadgen subcommand> [args] the pinned cadgen — everything else

Examples:

# render a PNG snapshot of a STEP for visual review
docker run --rm -v $PWD:/work -w /work <image> cad step snapshot STEP/plate.step tmp/plate.png

# one-off mesh export
docker run --rm -v $PWD:/work -w /work <image> cad stl build STEP/plate.step STL/plate.stl

# start the viewer manually (detached, prints the URL)
docker run --rm -it -v $PWD:/work <image> cad viewer --host 0.0.0.0 --port 3245 --json --detach

Project layout conventions and the model contract (decorated functions, out= paths relative to the script, one model per entrypoint) come from the upstream cad skill — install those skills in your agent of choice and point it at this container.

Updates

  • Update cadgen: change the pinned version (0.7.17) in Dockerfile and cad.sh (both must match), push — CI rebuilds. Upstream releases: https://pypi.org/project/cadgen/.
  • The pinned version is deliberate. cadgen reaches into build123d's internals (determinism shims, lazy stores); it is bounded to build123d>=0.11.1,<0.12 on purpose. Don't float.

Telemetry

cadgen ships with anonymous usage telemetry (PostHog) and a once-a-day update check on by default. This image ships both off (CADGEN_TELEMETRY=0, CADGEN_UPDATE_CHECK=0). Re-enable per-run with CADGEN_TELEMETRY=1 if you want.

Building locally

docker build -t cad-runtime .

CI (Forgejo Actions) builds both linux/amd64 and linux/arm64 on every push to main, then merges them into a multi-arch manifest, and pushes to the org registry as latest + <sha> (plus latest-<arch> / <sha>-<arch>). The arm64 build runs on the org's linux-arm64 self-hosted runner (Pi 5); if that runner is offline the whole run fails — check runner status before pushing.

Pi 5 disk heads-up: the arm64 runner's SD card is only 58G and fills up with Docker build cache fast. If a run fails with the Pi at ~100%, prune it (docker builder prune -af && docker image prune -af on the Pi) and push again to re-trigger.