Write a runtime configuration
Point native calls at the pinned Lean distribution, an owner-only output directory and a shared lock, with an optional call budget.
A runtime configuration is a small JSON file that you own, kept outside the repository. lema serve, check-runtime, build, run and test take it as --runtime. Every field is listed in the runtime configuration reference.
Before you start
- A distribution that passes
lema verify-distribution, with its path inDIST. If you ranscripts/cloud-setup.sh, that path is in$LEMA_DIST; otherwise see Install the pinned Lean by hand. - A host that meets the requirements, including the pinned
bwrapandsystemd-run --userwith delegated cgroups.
Steps
-
Create the output directory, readable only by you:
Shell OUT=$HOME/.lema/runs/first mkdir -p $HOME/.lema/runs mkdir -m 700 "$OUT"The runtime writes everything about its native calls here: the ledger
ledger.jsonl, each call’s log and records, work directories, the module cache (modules/) and built artifacts (artifacts/). -
Create the shared lock file. You need one per machine:
Shell touch $HOME/.lema/native.lock chmod 644 $HOME/.lema/native.lockEach native call holds this lock while it runs, and waits up to 600 seconds to get it. Give every configuration on the machine the same lock, so that their calls wait for each other instead of being refused.
-
Write the configuration. Paths must be absolute and contain no
... JSON does not expand~or$HOME, so write the paths out. This is howscripts/cloud-setup.shwrites its configurations:Shell CONFIG=$HOME/.lema/first.json printf '{"schema":"lema.runtime-linux/v2","distribution":"%s","output":"%s","shared_lock":"%s"}\n' \ "$DIST" "$OUT" "$HOME/.lema/native.lock" > "$CONFIG" chmod 644 "$CONFIG"The file holds exactly these four fields, plus
call_budgetif you add one. The output must not overlap the distribution, and the lock and the configuration must not be inside it. -
Optionally, cap the number of native calls with
call_budget, a non-negative integer. Only schemav2takes it:first.json {"schema": "lema.runtime-linux/v2", "distribution": "/home/you/.lema/toolchains/lean-4.34.1-linux-x86_64", "output": "/home/you/.lema/runs/first", "shared_lock": "/home/you/.lema/native.lock", "call_budget": 40}The budget counts every call ever recorded in this output’s ledger. Once it is used up, native calls are refused with
native call budget 40 exhausted.lema --socket $SOCK inforeportsnative_calls_usedandnative_call_budget. -
Check that the machine can run native calls. The check makes one real native call and records it in the configuration’s output, so give it a configuration of its own:
Shell PROBE=$HOME/.lema/probe.json mkdir -m 700 $HOME/.lema/runs/probe printf '{"schema":"lema.runtime-linux/v2","distribution":"%s","output":"%s","shared_lock":"%s"}\n' \ "$DIST" "$HOME/.lema/runs/probe" "$HOME/.lema/native.lock" > "$PROBE" chmod 644 "$PROBE" lema check-runtime --runtime "$PROBE"It exits 0 when the call ran. It exits 75 when the machine is busy (another call holds the lock, or the host is loaded): try again later. Any other refusal exits 1 with a message that names what differs.
-
Start the server with the configuration (
$STOREis your store directory and$SOCKthe socket to create):Shell lema serve --store $STORE --runtime $CONFIG --socket $SOCKLoading hashes the whole distribution again, so the server takes a while to start.
One output per suite run
Treat a configuration as a base, and give each native suite run a copy with a fresh output. A fault latches the output it happens in, and the budget counts one output’s ledger, so separate outputs keep each run’s records, faults and budget apart. A fresh output also starts with an empty module cache, so its first call that needs the decoder module (LemaCodebase) compiles it again.
Do not edit a configuration while a server uses it. Before every native call, the runtime compares the file’s SHA-256 with the one it loaded and refuses with runtime configuration changed. Write a new file and restart the server instead.
Refusals
| Message | Cause |
|---|---|
runtime configuration schema | schema is not lema.runtime-linux/v2 or lema.runtime-linux/v1. |
fields …, expected … | A missing or unknown field, or call_budget with schema v1. |
runtime path must be absolute: … | A relative path. |
…: No such file or directory (os error 2) | The output directory or the lock file does not exist yet. |
runtime path is writable by another user: … | A path is group- or world-writable, or belongs to another user. |
… and … overlap | The output and the distribution share a subtree. |
host executable/library drift: … | A pinned host file differs from its SHA-256 in crates/lema-check/src/pins.rs. |
disk reserve (output) | Less than 4 GiB is free where the output is. disk reserve (lock) is the same check for the lock’s directory. |
a native scope is still present | A native call under another lock is still running, or a call’s systemd scope was not cleaned up. |
Written against lema-lang at commit 5a94951, 17 Oct 2026.