README.md
This is an LM Studio tools-provider plugin that gives the model SageMath through a Podman sandbox.
It exposes these tools inside LM Studio:
run_sagemath — run SageMath code and return stdout/stderr.sage_podman_sandbox_self_test — run a small Sage factorization test.sage_podman_sandbox_status — check Podman, image availability, and active GUI settings.The central design rule is simple: LM Studio / Node never runs Sage directly on the host. The plugin starts a short-lived Podman container with no host mounts, no network, a read-only root filesystem, tmpfs-only writable directories, non-root execution, dropped capabilities, and hard resource limits.
Sandbox settings are exposed through LM Studio's plugin configuration UI. The plugin has a status tool so the model can diagnose whether Podman and the Sage image are available.
Default sandbox settings:
podmandocker.io/sagemath/sagemath:latest by default--network=none--read-only/tmp--cap-drop=all--security-opt no-new-privileges--pull=neverThe plugin refuses to execute Sage unless Podman reports rootless=true. However, no sandbox is mathematically perfect. This is intended to protect the host from ordinary and model-generated Sage/Python code.
Requires Linux with rootless Podman, a local SageMath container image, and fuse-overlayfs or a working rootless Podman storage driver. The plugin does not install Podman or download the image automatically. On Ubuntu-style systems:
sudo apt update sudo apt install podman fuse-overlayfs podman info --format '{{.Host.Security.Rootless}}' podman pull docker.io/sagemath/sagemath:latest
The plugin intentionally does not pull images during tool execution.
From this plugin directory:
npm install lms dev
LM Studio should show the plugin in its plugin list.
sage-podman-sandbox.podmandocker.io/sagemath/sagemath:latestsage_podman_sandbox_status first.Example prompt:
Use SageMath to factor x^6 - 2*x^5 - 13*x^4 + 8*x^3 + 32*x^2 - 8*x - 4 over QQ and print the discriminant.
Expected Sage code generated by the model:
R.<x> = QQ[] f = x^6 - 2*x^5 - 13*x^4 + 8*x^3 + 32*x^2 - 8*x - 4 print(f.factor()) print(f.discriminant())
This is approximately what the plugin does internally:
podman run --rm -i \ --pull=never \ --network=none \ --read-only \ --tmpfs /tmp:rw,nosuid,nodev,size=256m,mode=1777 \ --workdir /tmp \ --env HOME=/tmp/sage-home \ --env DOT_SAGE=/tmp/dot-sage \ --env SAGE_NUM_THREADS=1 \ --env OPENBLAS_NUM_THREADS=1 \ --env OMP_NUM_THREADS=1 \ --env MKL_NUM_THREADS=1 \ --env PYTHONNOUSERSITE=1 \ --user sage \ --cap-drop=all \ --security-opt no-new-privileges \ --pids-limit 96 \ --memory 1g \ --cpus 1 \ --ulimit nofile=1024:1024 \ --ulimit nproc=96:96 \ --ulimit fsize=134217728:134217728 \ --entrypoint /bin/bash \ -- \ docker.io/sagemath/sagemath:latest \ -lc 'set -euo pipefail; umask 077; mkdir -p /tmp/sage-home /tmp/dot-sage; chmod 700 /tmp/sage-home /tmp/dot-sage; cat > /tmp/user_code.sage; /usr/bin/sage -q /tmp/user_code.sage' <<'SAGE' R.<x> = QQ[] print(factor(x^4 - 1)) SAGE
The plugin refuses to execute Sage unless this command prints true:
podman info --format '{{.Host.Security.Rootless}}'
For reproducibility, replace docker.io/sagemath/sagemath:latest in the GUI with a pinned tested image digest.
An error I had during development said things like "kernel does not support overlay fs: 'overlay' is not supported over extfs...", even after fuse-overlayfs was installed. This was fixed by running:
mkdir -p ~/.config/containers cat > ~/.config/containers/storage.conf <<'EOF' [storage] driver = "overlay" [storage.options.overlay] mount_program = "/usr/bin/fuse-overlayfs" EOF