@leumas/lmx
LMX — the Leumas multi-interpreter scripting engine. General languages (lmx/lmy/lmz/lmm/lmc/lmn), the ecosystem languages that speak Leumas (lmq query, lmai prompt orchestration, lmg grids), and...
@leumas/lmx
Sixteen little languages with one runtime. A script's extension picks the interpreter — nothing to configure and no project file. hello.lmx is the full language; rename it hello.lmm and the same runtime reads it as a matrix machine.
Public face: lmx.leumas.tech — a browser sandbox that runs the local modes with no account, and the lmx CLI as a single downloadable file.
The sixteen
| Ext | Name | What it is |
|---|---|---|
.lmx | Full Language | General-purpose language: variables, math, if/for/while, functions, imports. |
.lmy | Sequential | One statement per line — quick, calculator-style scripting. |
.lmz | Event-driven | Register on/emit handlers; reactive event-bus scripting. |
.lmm | Math / Matrices | Vector accumulator + trigonometry + matrix algebra. |
.lmc | Constraint Solver | Declare variables + equations; solve for the unknowns from what you know. |
.lmn | Notifications | Declarative toast / alert / sound / desktop-message directives. |
.lmq | Query | Read stored collections — FROM / WHERE / SELECT / ORDER BY / aggregates. |
.lmai | Prompt Orchestration | Declare prompts and shapes, ASK a model, branch on the answer. |
.lmg | Grids | Author and run a programming grid as text — cells, $refs, dependency order. |
.lma | Any-tool | Call anything this install has — adapters, actions, MCP tools, capabilities. |
.lmi | Install | Ask the RUNNING deployment what it is and what it can actually do. |
.lms | Shell Automation | Runs OS shell commands (RUN / CAPTURE / IF_SUCCESS). |
.lmk | GUI Automation | Controls mouse/keyboard via robotjs (native desktop only). |
.lmd | Command Dispatch | Discovers namespaced commands and spawns them (experimental). |
.lmnet | Network | ping / fetch / post over the network (SSRF-sensitive). |
.lmt | Timers | after/every time blocks that dispatch other scripts (experimental). |
That table is generated from src/host/interpreters.catalog.js, which is also what the API's /api/lmx/interpreters route, the Studio picker and INTERPRETERS.md read. There is one list.
Three tiers, and the difference is not politeness
Local (lmx lmy lmz lmm lmc lmn lmg) — no host access at all. These run anywhere: the browser sandbox, the CLI, the API.
Install-backed (lmq lmai lma lmi) — their vocabulary is a running Leumas. lma has no verb table: its verbs are every adapter tool, every stored functioncall, every automation action, every MCP tool and every capability the install currently holds, so registering an adapter makes existing scripts able to call it with nothing rebuilt. These need an identity, because they read somebody's data, spend somebody's model credits and call somebody's tools. They are refused by name in the public sandbox and by the CLI unless it is pointed at an install with --studio.
Privileged (lms lmk lmd lmnet lmt) — these touch the host. Admin role and an explicit env flag (LMX_ENABLE_SHELL / LMX_ENABLE_GUI / LMX_ENABLE_NET), both off by default. That is a security control, not a paywall — LMX is free.
Running a script
Three entry points, and the difference between the first two is the whole design:
import { runScript } from '@leumas/lmx'; // a WORKER: isolated, hard deadline, terminate()
import { runLocal } from '@leumas/lmx/local'; // IN-PROCESS: no deadline, no bridges, streams to stdout
import { INTERPRETERS } from '@leumas/lmx/catalog'; // the catalogue alone — no express, browser-safe
runScript is right for a server running somebody else's script: the timeout is the only real bound on a while (true), and it never rejects — a syntax error is {ok: false, error}, which is what lets a caller tell a failed script from a request that never arrived.
runLocal is right for a command: a person running their own script on their own machine wants stdin, a TTY, an exit code and no five-second cap. It is also the only shape a single-file build can carry.
[warning] Import the leaves, not the barrel, unless you serve HTTP..re-exportscreateLmxRouter, which imports express — free inside the API, and a whole web framework inside a CLI binary.@leumas/lmx/localand@leumas/lmx/catalogcarry neither.
HTTP
| Route | Auth | What |
|---|---|---|
GET /api/lmx/interpreters | member | the catalogue, with each mode's enabled flag |
GET /api/lmx/demos · /demos/:id | member | the bundled example scripts |
POST /api/lmx/run | member | {mode, source, inputs?} — every safe mode, bridges wired to the caller |
GET /api/lmx/public/interpreters | none | only what the sandbox will run |
POST /api/lmx/public/run | none | the anonymous sandbox — see below |
The public pair is a separate router (createPublicLmxRouter), not the authenticated one with a softer guard: createLmxRouter turns every route into an open one when handed a non-function requireAuth, and making that conditional would arm exactly that trap. Its bounds are inside the router, not around it — a narrowed mode list, no bridges and no adapter(), a hard 3s deadline, a source cap and a concurrency cap. It is mounted only where the role declares publicSandbox, so a customer's appliance never carries it.
The bridges are FACTORIES, (user) => bridge, built per request. One bridge built at mount time and shared would hand every user the first user's permissions, key and wallet.
The CLI
lmx hello.lmx # the extension picks the interpreter
lmx -e 'print(6 * 7)' -m lmx # a string
lmx modes # every interpreter and where it runs
lmx --studio https://api.leumas.tech --token <t> report.lmq
Shipped as one file per machine (pnpm lmx:binary), built by the same Node SEA lane as LeumasNode. Exit codes are a contract: 0 ran, 1 the script or the request failed, 2 you called it wrong.
Traps
- An
lmaireply is not proof a model ran.providerRegistry.resolve()never fails —auto
falls back to an echo stub. A shaped ask on the stub echoes the prompt, which contains the SHAPE example, so a flawless-looking classification can be your own example handed back. stub: true and tokens: 0 are the only tells, and the runner prints a warning by itself.
lmimust never answer "yes" by default. No entitlement engine wired meansunknown, never
true. And entitled ≠ fulfillable: CAN and PROVIDERS FOR are different questions.
{{ $C1 }}, not{{C1}}, in a template cell — the bare form renders the literal text.- The in-script
adapter()builtin is unmetered.lma'sUSEcharges against the same
tool:<ref> target the HTTP route does; the older builtin does not, and changing it would alter existing scripts' behaviour.
Verify
pnpm smoke:lmx (every safe mode, every bridge, every gate, docs drift) · pnpm smoke:lmx-public (the anonymous lane: what it refuses) · pnpm smoke:lmx-cli --binary (the shipped binary, which is the only thing that sees the SEA defects) · node --test shared/engines/lmx/src/test/*.test.js.
Agent skill: leumas-lmx. Per-language references: docs/{lma,lmi,lmq,lmai,lmg}.md.