{
  "schema": "leumas.docs.page/1",
  "id": "skill:leumas-lmx",
  "slug": "skills/leumas-lmx",
  "kind": "tools",
  "bucket": "skill",
  "title": "leumas-lmx",
  "name": "Leumas LMX",
  "eyebrow": null,
  "chip": null,
  "summary": "Write, run or extend an LMX script — the 16 interpreters, incl. lma (call any tool), lmi (ask the install), lmq (query), lmai (model), lmg (grids). Read before writing one or adding a mode.",
  "keywords": [
    "leumas-lmx",
    "interpreters",
    "lmai",
    "bounds script",
    "grids",
    "adding interpreter",
    "writing",
    "six traps"
  ],
  "audience": "both",
  "funnel": {
    "product": null,
    "cta": null
  },
  "body": "\n# Writing LMX\n\nLMX (`shared/engines/lmx`, `@leumas/lmx`) runs **16 small languages** in a sandboxed, time-bounded\nworker thread. Nine are general computing. **Five speak Leumas**, and two of those are *dynamic* —\ntheir vocabulary is a live registry, so what they can do grows with the ecosystem:\n\n| Want to… | Use | Needs |\n|---|---|---|\n| **call any tool this install has** | **`lma`** dynamic | the `tools` bridge → `POST /api/lmx/run` |\n| **ask what this deployment can do** | **`lmi`** dynamic | the `install` bridge → `POST /api/lmx/run` |\n| read stored rows | `lmq` | the `db` bridge |\n| drive a language model | `lmai` | the `ai` bridge |\n| compose a programming grid | `lmg` | nothing — runs anywhere |\n| general logic + one adapter call | `lmx` | `adapters` for `adapter()` |\n| a quick calculation | `lmy` · `lmm` · `lmc` | |\n| events, notifications | `lmz` · `lmn` | |\n| shell, GUI, network, timers | `lms` `lmk` `lmd` `lmnet` `lmt` | **admin + an env flag** |\n\nFull generated list with syntax and snippets: `shared/engines/lmx/src/INTERPRETERS.md`.\nDeep references: **`reference/lma.md`** · **`reference/lmi.md`** · **`reference/lmq.md`** ·\n**`reference/lmai.md`** · **`reference/lmg.md`**.\n\n## Reach for `lma` first\n\nBefore writing a bespoke script, remember `lma` can already call every adapter tool, every stored\nfunctioncall and user integration, every automation action, every MCP tool and every vendor-neutral\ncapability — ~1,800 verbs, resolved live:\n\n```lma\nPLANES                                      # what planes exist here\nDISCOVER \"invoice\"                          # search all of them\nDESCRIBE a-text.Base64Encode                # declared params\nUSE a-text.Base64Encode { \"text\": \"{{input}}\" } -> e\nEACH row IN rows USE a-text.Summarize { \"text\": \"{{row.body}}\" } -> summaries\nTRACE                                       # what actually ran, and which provider served a cap:\n```\n\nAnd `lmi` answers *\"what can this install do\"* rather than *\"what can Leumas do\"*:\n\n```lmi\nINSTALL\nCAN ai.text.generate            # this USER's entitlement, three-state\nPROVIDERS FOR email.send        # who would actually serve it here\nLIST tools WHERE category = \"media\" LIMIT 20\n```\n\n## Run one\n\n```bash\nleumas-lmx ./script.lmg                     # lmg and the general modes need no host\ncurl -s -X POST localhost:3000/api/lmx/run -H 'content-type: application/json' \\\n  -d '{\"mode\":\"lmi\",\"source\":\"INSTALL\"}'    # lma/lmi/lmq/lmai need bridges\n```\n\n`GET /api/lmx/interpreters` is the live catalog for a given install; `GET /api/lmx/demos` returns the\nbundled scripts with source — the fastest working example of any mode.\n\n## The six traps\n\n1. [critical] **An `lmai` reply is not proof a model ran.** `resolve()` never fails — `auto` falls back to an\n   echo stub. Branch on `usage.stub`. Worst case, verified live: a shaped ask on the stub returns your\n   own `SHAPE` example as a flawless-looking answer, with `stub:true, tokens:0` the only tell.\n2. [critical] **`lmi` must never answer \"yes\" by default.** No entitlement engine wired ⇒ `unknown`, never\n   `true`. An unknown reported as yes is a confident wrong claim about someone else's deployment.\n3. [critical] **Entitled ≠ fulfillable.** `CAN` and `PROVIDERS FOR` are different questions; a user can be\n   entitled to a capability this install has nothing connected to serve.\n4. [critical] **`lmg` cells go in `specialConfig`, not `props`.** Both execute; only `specialConfig` (and a\n   top-level `code`) is read by the dependency graph, so a props-authored grid prints an empty `GRAPH`.\n5. **`lmq` timestamps are epoch milliseconds.** Use `days_ago(n)`, not a date string.\n6. **A bridge-needing mode REFUSES without its bridge** rather than returning empty. *\"needs the …\n   bridge\"* means you are on the CLI or the `lmx` adapter — use `POST /api/lmx/run`.\n\n## What bounds a script\n\nEverything a script can reach is a **named channel** the host wired. Nothing else escapes the worker.\n\n| Channel | For | Bounded by |\n|---|---|---|\n| `adapter` | the `adapter()` builtin | — *(unmetered; see below)* |\n| `db` | `lmq` | read-only by construction · `/db`'s deny lists · per-row `canRead` · 5000 rows |\n| `ai` | `lmai` | `resolveKeyForUser` · 20 calls · 60s |\n| `tools` | `lma` | host scope + `USING` · 50 calls · `passnode.charge` · 30s |\n| `install` | `lmi` | read-only; there is no method that changes anything |\n\nAll are **factories** called per request with `req.user`. Never cache one across users.\n\n[critical] **Metering asymmetry.** `/api/adapters/:system/:fn` is priced by `passnode.guard`, but that lives in\nthe HTTP router — `registry.run()` is not metered, so non-HTTP callers are free. `lma` closes this for\nitself by charging the same `tool:` target; the older `adapter()` builtin is still unmetered.\n\n## Adding an interpreter\n\n| File | Add |\n|---|---|\n| `src/interpreters/<id>/{index,parser,runner}.js` | `run({ filename, source, bridges, inputs })` |\n| `src/host/interpreters.catalog.js` | one entry — lights up the API, Playground, tooltips and Reference tab |\n| `src/host/worker.js` | one `case` in `dispatch()` (+ a channel proxy if it needs one) |\n| `src/host/demos.js` | one `EXT_TO_MODE` entry |\n| `src/index.js` | `resolveMode()` + CLI dispatch |\n\n**Prefer a dynamic design.** If the new language needs a vocabulary, ask whether a registry already\nholds it — `planes.js` turns any registry's exported functions into verbs, and `install.js` takes the\nindex-service source map. A language built that way never goes stale. Put policy in the *mounting\napp*, never in the engine: `@leumas/lmx` depends only on `express` and `@leumas/grids`.\n\nThen a demo in `src/scripts/`, a case in `ops/infra/scripts/check-lmx.mjs`, tests in `src/test/`, and\n\n```bash\npnpm docs:lmx        # regenerate INTERPRETERS.md from the catalog\npnpm smoke:lmx       # every safe mode, every bridge, every gate, + docs drift\nnode --test src/test/*.test.js\npnpm skills:sync && pnpm check:skills\n```\n\n`INTERPRETERS.md` is **generated**. Editing it by hand is how it came to document 7 of 11 modes.\n",
  "source": {
    "path": ".claude/skills/leumas-lmx/SKILL.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 6308,
    "hash": "a345402b5b8d05cc71fd4163940200fb569a5051"
  },
  "urls": {
    "html": "/p/skills/leumas-lmx",
    "json": "/docs/skills/leumas-lmx.json",
    "md": "/docs/skills/leumas-lmx.md"
  },
  "links": {
    "composes": [],
    "usedBy": [],
    "product": [],
    "howTo": [],
    "skills": []
  }
}
