Skip to content

Compatibility

This page lists what Thermite needs and what it has been tested with. Each row says how it is tested, or not tested where nothing in the repository tests it. A version Thermite does not check is marked so: it may work, but nothing shows it. The glossary explains the terms.

WhereVersionHow it is tested
Your computer, for the thermite command, the tests and the scripts22.19 or later (engines in package.json). The agent libraries need itCI runs the type check, lint and tests on Node.js 22 and 24
Inside the imagesThe Node.js 22 of node:22-bookworm-slim, pinned by digest. The exact 22.x release is whatever that digest holdsEvery image build

The images carry their own copy of Thermite, so a release’s compose stack needs no Node.js on your computer. Node.js is needed only for the command line, and in a checkout of the source code for npm run dev:init and the test scripts.

SystemStatusHow it is tested
LinuxSupportedCI runs on Ubuntu 24.04
macOSSupported, with Podman or Docker running their Linux virtual machineNot in CI. The compose test scripts work with a Podman machine: they trim its disk after each run
WindowsNot testedNothing in the repository tests it

A machine that control sets rigs up on, over SSH or with a join command, needs Linux with systemd and Podman. A rig that runs as a user other than root needs lingering on for that user.

Machine’s systemWhat control can install for youHow it is tested
Debian, UbuntuPodman (apt), NVIDIA’s container toolkit, lingeringMachines acceptance: control installs Podman on a Debian 12 container that stands in for the machine
Fedora, RHEL, CentOS, Rocky Linux, AlmaLinux, Amazon LinuxPodman (dnf), NVIDIA’s container toolkit, lingeringRig deploy acceptance: control turns lingering on and sets a CPU rig up on a Fedora 41 container with systemd and rootless Podman. The dnf installs are not tested
Any other LinuxLingering only. Install the rest yourself: control says control has no recipe for <os>: install it yourselfNot tested

Installs need sudo without a password. See Add a rig on a machine over SSH.

ToolStatusHow it is tested
Docker with docker composeSupportedCI runs the compose smoke test with it
Podman with podman composeSupportedEvery compose acceptance script takes it, and it is their default. Not in CI
podman-composeSupportedThe compose smoke test takes it (COMPOSE="podman-compose"). Not in CI
Podman on a machine that hosts rigs4.4 or later, for its Quadlet unitsThe rig deploy acceptance, on Fedora 41’s Podman. Neither the join script nor setting up over SSH checks the version: the join script checks only that Podman is there

No minimum version of Docker, Docker Compose, Podman or podman-compose is stated or checked for the compose stack. compose.yaml uses secrets from files, profiles, internal networks, extra_hosts with host-gateway, dropped and added capabilities, no-new-privileges, restart policies and ${VAR:-default} defaults. A release’s compose file uses the same, images pinned by digest alone (name@sha256:…), and network_mode: none for its init service, which you start with compose run --rm.

Two acceptance tests need Podman and refuse Docker: rig deploy and cluster. Install Thermite on one machine gives the commands for each tool.

PointStatusHow it is tested
Kubernetes versionNo minimum is stated. Control’s image carries kubectl v1.37.1A kind cluster on Podman (cluster acceptance), with kind’s default node image. The kind version is not pinned
APIs usedv1, apps/v1, networking.k8s.io/v1; resource.k8s.io/v1 for GPUs through dynamic resource allocation
Placementscreated (control makes the namespace), slot (a namespace made for Thermite), joined (a namespace join command)Cluster acceptance tests created and slot, with CPU rigs only. In the slot it also moves the rig onto newly tagged images (Update to these images), and checks that the rig reports again with its volume claim and secret unchanged
GPUs through the device plugin (nvidia.com/gpu)Control can set a rig up this wayNot tested
GPUs through dynamic resource allocation (a device class)Control can set a rig up this wayNot tested
NetworkPolicyControl writes them for created and joined placements, and checks a slot’s rules before it uses the slot. They need a network plugin that enforces themCluster acceptance: a created namespace gets its policies, and a slot without the needed rule is refused
Running control itself on KubernetesNo manifest or chart ships. Goal 058 plans oneNot tested

See Add a rig on a Kubernetes cluster.

PointStatusHow it is tested
GPU vendorNVIDIA only: nvidia-smi, /dev/nvidia* device nodes, CDI on machines, the device plugin or dynamic resource allocation on clusters
GPUs on one rigUp to 8 for the judge and 8 for the agents. Up to 16 on a rig control sets up on a machine or cluster; 8 on a joined namespaceThe multi-GPU acceptance, with four fake GPUs (plain files and a stand-in nvidia-smi)
Several judge GPUsThey must be the same model. Otherwise only the first one judges, and the rig’s hardware report says whyNot tested
CUDAA CUDA 12.x development image as the harness’s base. The published CUDA harness is built on nvidia/cuda:12.6.3-devel-ubuntu22.04, pinned by digest in the release workflow. CUDA 13 dropped older architectures. RunPod test pods ask for hosts with CUDA 12.6 or laterNo test in the repository. A RunPod test pod checks one real GPU host: see Test a GPU on RunPod
GPU architecture of the CUDA smoke kitBuilt for sm_60
NVIDIA driverNo minimum is stated or checked. A machine’s check reports the driver and CUDA versionsNot tested
NVIDIA container toolkit1.20.1-1 when control installs it, with a CDI specification for PodmanNot tested: the machines acceptance installs only Podman
Landlock (Linux kernel)Used for the GPU fence when the kernel has itMulti-GPU acceptance; the RunPod test’s probe
GPU rigs under composeNot available. Goal 037 plans them

Without Landlock, and with device nodes that cannot be given their own groups, a GPU rig neither times nor allows development runs; it never falls back to sharing. Sharing a device explains why, and Give a rig several GPUs shows how to set the split.

ImageArchitecturesHow it is tested
Controlamd64 and arm64. Its build stops on any other: kubectl is pinned for these two onlyCI builds it on amd64 (GitHub’s ubuntu-24.04 runners). The release workflow builds it for amd64 and arm64
Harness, CPUamd64 and arm64. It installs the arm64 package of OpenCode, Claude Code and the Codex CLI on arm64, and the x64 package on any other architectureCI builds it on amd64. The release workflow builds it for amd64 and arm64
Harness, CUDAamd64The release workflow builds it for amd64 only
Supervisoramd64 and arm64. Claude Code, when built in, comes as its arm64 or x64 packageCI builds it on amd64. The release workflow builds it for amd64 and arm64
One-container rig, CUDAamd64, as the CUDA harness it is built onCI builds the rig image on the CPU harness, on amd64. The release workflow builds it on the CUDA harness, for amd64 only

The release workflow builds the arm64 images under emulation, on amd64 runners; no test runs them. Each published image of control, the CPU harness and the supervisor is one name for both architectures, and Docker or Podman pulls the one that fits the machine. Push the images to your own registry builds them yourself, and Harness image lists what each contains.

Control, each rig’s harness and each rig’s supervisor report their Thermite version, the commit their image was built from, and their protocol: the version of the contract between control and a rig. Control compares each rig’s with its own. The REST API, MCP’s list_rigs and thermite rig list show a rig as behind when it runs an older version that control still works with, with a notice to update its images. Rig versions gives every field and message. On the dashboard, a rig’s page shows its version, and a banner when it is behind, ahead or refused, with Update to control’s version for a rig control set up (A rig’s page).

Control can move a rig it set up, on a machine or a cluster, onto the images it now deploys (Update to control’s version on the rig’s page; on a cluster, Update to these images too); joined rigs keep their images (goal 035).

CaseWhat happensHow it is tested
A rig runs a build from before version checksIt reports no version. Control shows its version as unknown, and never refuses it for that: its reports and commands go through as beforesrc/control/versions.test.ts
A rig runs an older version, on a protocol control works withControl takes its reports and sends it commands, and marks it behindsrc/control/versions.test.ts
A rig’s protocol and control’s do not meetControl refuses its reports and commands, and says why in the rig lists, in the audit log (rig_refused) and in its supervisor’s log. When the rig reports a build control works with, the refusal endssrc/control/versions.test.ts
Control is updatedA new release keeps working with the protocol before its own, so an update of control never cuts off the rigs on the release before it. At start, control checks the rigs it refused againsrc/core/version.test.ts and src/control/versions.test.ts
A rig’s supervisor is newer than controlControl takes its figures, daily reports and exports, drops the fields it does not know, and marks the rig ahead. The harness’s signed reports stay exact: a field a newer harness signs fails the signature. See Fields control does not knowsrc/control/versions.test.ts
Control’s knowledge base has kinds of item a rig’s build does not knowThe rig’s past-research sync leaves those items out, logs each kind once, and goes on. When the rig runs images that know the kind, its runs sync again from the beginning. See What syncs and how oftensrc/supervisor/kb-sync.test.ts
A rig’s harness is older than controlIt refuses a command kind it does not have with malformed command, and a payload its own schema does not allow with bad payload: …. A harness from before messages could be kept in force refuses unkeep_message and a message_agent to all, teachers, auditor or panel, and drops keep from other messages, which then are not kept in force; its message lines carry no message number, so a run’s Live shows them without To …, and it writes no read lines. A harness from before the experiment queue refuses queue_add, queue_move, queue_edit, queue_drop, queue_accept and drop_directive with malformed command, and starts a run with an empty queue whatever assign_campaign’s queue holds. Control signs a rule’s direction as its name, so a harness from before rules named directions takes it, but its planner doesn’t design a new direction: such a rule holds by name only, and control lists its direction with to_design until an experiment has itNot tested
A harness opens a ledger an older harness wroteIt upgrades the ledger. The owner’s messages from before read receipts count as read by the lane or the planner they were delivered to, and a message to the advisors as read by each of them, so none is given againThe harness’s tests
A harness opens a ledger a newer harness upgradedIt refuses the ledger, and the harness does not start: this ledger is at schema version <n>, newer than this code's <m>: run a newer Thermite, or restore the ledger from before the upgrade. A rig moved back onto an older image can hit thisThe harness’s tests
  • The oldest Docker, Docker Compose, Podman or podman-compose that runs the compose stack.
  • The oldest Kubernetes that runs a rig, and whether GPU rigs work on a real cluster.
  • The oldest NVIDIA driver that works.
  • Windows, and whether the arm64 images work: no test runs them.
  • How much memory and disk the stack needs. Lane build caches can reach 8 GB each. A cluster rig with resources set needs at least 1.5 CPUs and 6 GiB of memory.