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:
The 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:
The plugin intentionally does not pull images during tool execution.
From this plugin directory:
LM Studio should show the plugin in its plugin list.
Example prompt:
Expected Sage code generated by the model:
This is approximately what the plugin does internally:
The plugin refuses to execute Sage unless this command prints true:
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:
podmandocker.io/sagemath/sagemath:latest by default--network=none--read-only/tmp--cap-drop=all--security-opt no-new-privileges--pull=neversage-podman-sandbox.podmandocker.io/sagemath/sagemath:latestsage_podman_sandbox_status first.sudo apt update
sudo apt install podman fuse-overlayfs
podman info --format '{{.Host.Security.Rootless}}'
podman pull docker.io/sagemath/sagemath:latest
npm install
lms dev
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.
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())
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
podman info --format '{{.Host.Security.Rootless}}'
mkdir -p ~/.config/containers
cat > ~/.config/containers/storage.conf <<'EOF'
[storage]
driver = "overlay"
[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs"
EOF