Server methods
The request protocol of lema serve and every method it answers, with parameters and results.
lema serve owns one store and one runtime configuration and answers requests on a Unix socket. The dispatch is Server::handle in crates/lema-cli/src/main.rs; the methods it hands on are in crates/lema-store and crates/lema-http/src/release.rs. This page describes them at lema-lang HEAD 5a94951. From the command line, any method is sent with lema call METHOD (the CLI reference).
Protocol
A client opens one connection per request. It writes one JSON object, shuts down its write side, and reads one JSON response.
{"method": "find", "params": {"prefix": "app."}}{"ok":true,"result":{"app.main":{"generation":1,"id":"…"}}}A refused request is answered with {"ok": false, "error": "<message>"}. Responses are canonical JSON: sorted keys, no whitespace.
| Rule | Value |
|---|---|
| Largest request | 256 MiB. A larger one is answered with the error request too large. |
| Time to send the request | 120 seconds in all, then request not complete in time. |
| Time to read the response | 120 seconds in all; a client that does not read it cannot hold the server. |
| Order | One request at a time, so the store never has two writers. |
params | Any JSON value; an absent params is null. |
| Errors before dispatch | request must be an object, request needs a method, unknown method NAME. |
The socket is created with the process’s file mode mask set to 077, so it is owner-only from the start, and the server checks that its mode grants nothing to group or others. Every client therefore runs as the store’s OS user. At start the server replaces a stale socket file, and refuses a path where a server still answers or that is not a socket.
Conventions
- An ID is 64 lowercase hexadecimal digits. Object IDs are defined on the objects page.
- A reference is
{id}or{id, role}: an object, or one role of it (for example a structure’s constructor). - Every method that moves an alias names what it expects the alias to hold.
expect: nullmeans the name must be new.expect: {id, role?}means it must name that reference, andexpect: {id, role?, generation}adds the generation, asfindreturns it.replaceuses its own fields,expectedandexpected_generation. overwrite: truein place ofexpectapplies the change whatever the alias holds, and the history records it as an overwrite. A missing or stale expectation is refused.idempotency_keyis a string of 1 to 256 bytes without control characters.alias,submit/import,publish,replace,ref.create,ref.publishandref.adoptaccept it. It is bound tosha256("LEMA-PUBLICATION-v1\0" ‖ operation ‖ "\0" ‖ canonical JSON of the params without the key). A retry with the same key and the same params returns the first response and applies nothing; the same key with other params is refused. Keys never expire and are shared by every client of the store.actorandtokenauthenticateref.create,ref.publish,ref.adoptandreview.create. The token is compared with the SHA-256 the store keeps, and is never recorded.- Only
elaborate,submit/import,publish,executableandreverifycan make native calls. Every other method reads or writes the store without Lean. - The bundle, project, report, review and release methods refuse unknown fields.
Objects and aliases
info
Reports the store and the server. It takes no params.
| Result field | Meaning |
|---|---|
namespace | The namespace object’s ID. |
objects | Stored objects. |
accepted | Stored objects that are accepted. |
aliases | Aliases. |
allowed_axioms | The store’s axiom policy. |
tooling_sha256 | Digest of the Lean checking sources (exporter, decoder, replay). |
modules | Modules in the module cache. |
native_calls_used | Calls reserved in the runtime output’s ledger. |
native_call_budget | The configuration’s call_budget, or null. |
ids
Returns every stored object ID, as a list. It takes no params.
get
Returns stored objects, each re-validated against its ID. Its one param, ids, is required: a list of IDs. The result maps each ID to its object.
show
Returns one object with what the store knows about it. Its one param, id, is required: an object ID.
| Result field | Meaning |
|---|---|
object | The object. |
receipt | Its receipt, or null when it has none. |
names | The aliases whose target has this ID, with any role. |
find
Returns aliases by name prefix. Its one param, prefix, is optional; without it every alias is returned. The result maps each name to {id, role?, generation}: the form an expectation takes.
deps
Returns every object ID that an object links to directly: its namespace, statement, template, binding, proofs, realizations and generated family where present, and the references inside its expressions and family entries. Its one param, id, is required: an object ID.
dependents
Returns the stored objects that link directly to an object. Its one param, id, is required: an object ID.
alias
Creates or moves one alias.
| Param | Required | Meaning |
|---|---|---|
name | yes | 1 to 512 bytes, no control characters. |
target | yes | The reference {id, role?} it should name. |
expect | one of these two | What it holds now (see Conventions). |
overwrite | one of these two | true: change it whatever it holds. |
idempotency_key | no | See Conventions. |
| Result field | Meaning |
|---|---|
name | The alias. |
id, role | Its target now. |
generation | 1 when created, one more at each move. |
changed | false when the alias already named the target, which moves nothing. |
submit and import
Accepts a draft by kernel replay, whole or not at all. import is the same method under another name.
| Param | Required | Meaning |
|---|---|---|
objects | no | A map from ID to object: the draft. It may repeat stored objects. Default: empty. |
roots | yes | The IDs to accept. Their closure is filled from the store where the draft lacks an object. |
aliases | no | A map from name to {target, expect} or {target, overwrite: true}. |
overwrite | no | true: aliases maps names to bare references {id, role?} (an exported draft’s form), and each change is an overwrite. |
idempotency_key | no | See Conventions. |
Expectations are checked before any native call and again when the changes apply. The closure is replayed source-free by the pinned Lean 4.34.1 kernel, incrementally through the module cache, within the store’s axiom policy above the fixed floor. All alias changes of the request apply together in one history line.
| Result field | Meaning |
|---|---|
stored | Objects newly written to the store. |
receipts | Receipts this replay issued. |
roots | The roots, as given. |
aliases | With aliases: each name’s {id, role?, generation, changed}. |
export
Returns the accepted objects reachable from roots, for transfer to another store. Its one param, roots, is required: a list of IDs. The result maps each ID in the closure to its object. It is refused when any object of the closure is not accepted. Receipts are not exported; a receiving store replays the objects.
Authoring and checking
elaborate
Turns restricted Lean into an untrusted draft of canonical objects. Nothing is stored. The source’s rules are on the authoring rules page.
| Param | Required | Meaning |
|---|---|---|
source | yes | The Lean text. It imports nothing; the server writes the header. |
prefix | no | The namespace whose constants are exported, conventionally LemaDraft. |
roots | no | Further names to export. |
bindings | no | A map from Received.<name> to {id, role?}: accepted objects the source uses by identity. |
receive | no | Up to 64 bundles, each {bundle, as?, rename?}, bound as described below. |
seeds | no | A map from family name to a 64-hex seed. |
seed_salt | no | Text from which a family’s seed is derived when seeds does not give it. |
Each receive item binds every export N of its bundle as Received.<as>.N, or as Received.N without as. rename maps an export name to the name it takes, and prefix is another spelling of as. A derived seed is sha256("lema.seed/v1\0" ‖ seed_salt ‖ "\0" ‖ name).
Before any native call the server checks every binding. A name bound twice, an unknown bundle, a target that is not accepted, or a role its object lacks is refused. The server then replays any received object that no module holds yet into a new module, which is a native call only when there is such an object. It adds one Lean alias per binding, runs the exporter in one sandboxed call with a 300-second limit, and builds the objects.
| Result field | Meaning |
|---|---|
objects | A map from ID to object: the draft. |
names | A map from each name the draft defines to its reference {id, role?}. |
received_bundles | With receive: the bundles received, sorted. |
publish
Runs elaborate and then submit inside the server, so a client never holds the draft.
| Param | Required | Meaning |
|---|---|---|
source, prefix, roots, bindings, receive, seeds, seed_salt | as elaborate | The elaboration. |
aliases | no | A map from a draft name to {expect} or {overwrite: true}. The target is the draft’s own reference for that name. A request-level overwrite is refused. |
idempotency_key | no | See Conventions. |
authoring | no | {path, notes?}: also keep the source as an authoring bundle at the relative path, with optional notes mapping draft names to text. |
The submitted roots are the IDs of the draft’s names that have no role. Each alias must name an object the submission reaches, or one already accepted. Expectations and the authoring shape are checked before the first native call, and the whole authoring bundle before the submission’s native call; only its write follows acceptance.
| Result field | Meaning |
|---|---|
names | As elaborate. |
stored, receipts, roots | As submit. |
received_bundles | With receive. |
authoring | With authoring: the authoring bundle’s ID. Its validation is elaborated. |
aliases | With aliases: each name’s {id, role?, generation, changed}. |
view
Renders accepted objects in the contract syntax.
| Param | Required | Meaning |
|---|---|---|
render | yes | The names to render. Each must resolve to an accepted object. |
names | no | A map from name to {id, role?}, as elaborate and publish return it. It overrides the store’s aliases. Objects with no name are shown from their ID. |
The result maps each requested name to {text, names}, or to {error} when the object cannot be shown. In names, each name in the text maps to {id, role?} for a stored object or {lean: name} for one of Lean’s constants. view does not check its output; the round-trip tests do.
executable
Compiles restricted Lean from source alone and checks what the compiled code reaches. It makes one sandboxed native call (600 seconds).
| Param | Required | Meaning |
|---|---|---|
source | yes | The Lean text. bindings and receive are refused, even empty. |
roots | yes | 1 to 64 declaration names. |
seeds, seed_salt | no | As elaborate. |
profiles | no | Distinct Std.Guarantee.IR profile names: NoCopySliceCall, NoBigIntPrimitives, NoBoxOrCtorInCycles. |
The IR closure of the roots must pass the executable vocabulary (crates/lema-check/src/vocabulary.rs), and the roots’ whole object closure must be accepted. The result has roots (name to ID), objects (the closure’s size), declarations, externs, vocabulary (the vocabulary’s digest), call and claim. With profiles it also has guarantees, one receipt per profile, and guarantee_records, the ID of each receipt stored as a guarantee record. A violated or unsupported profile is reported in its receipt, not refused.
reverify
Replays accepted objects from scratch in one native call (600 seconds), with no modules, and compares the result with the store. Its one param, roots, is optional: a list of IDs whose closure is replayed. Without it, every accepted object is replayed. The closure may hold at most 20,000 objects; a larger store is replayed in parts with roots. Each kernel receipt’s axiom footprint must equal the fresh one, and every other object must be used directly by a declaration replayed in the same call. Any difference is an error.
| Result field | Meaning |
|---|---|
objects | Objects in the closure compared. |
receipts | Fresh kernel receipts. |
notes | Objects accepted through a declaration replayed now. |
call | The native call’s name. |
Evolution
replace
Moves an alias from one implementation to another, only with an accepted proof of exactly the replacement claim. One history line records the move and its witness.
| Param | Required | Meaning |
|---|---|---|
name | yes | The alias to move. |
expected | yes | The implementation it names now. |
target | yes | The implementation it moves to (not expected). |
contract | yes | The contract. |
claim | yes | The claim definition. |
proof | yes | An accepted theorem proving claim. |
representation | yes | The representation relation. |
relation | no | The relation at the claim’s head, such as Replaces (lean/core/Replaces.lean). |
expected_generation | no | The alias’s generation now. |
idempotency_key | no | See Conventions. |
Every field but name is an object ID, and every one of them must be accepted. Without relation, the claim is contract S T expected target representation. With it, the claim is relation a1 … ak contract expected target representation, possibly over parameters. The contract, implementations, relation, claim and proof must have no universe parameters. The result is the witness: name, old, new, contract, claim, proof, representation, namespace and scope, and with a relation also relation and prefix (the leading arguments), and parameters when the claim has any.
Contract evolution
| Method | Params | Result |
|---|---|---|
refine | old, new, proof | A witness {old, new, proof, namespace, shape, scope} |
correct | old, new | A witness {old, new, namespace, scope, clients} |
evolution | id | {refined_by, refines, corrected_by, corrects, superseded} |
The params of refine and correct are IDs of accepted objects, and correct refuses a proof. Each records one history line. A refine witness’s shape is predicate (∀ x…, new x… → old x…, with parameters) or protocol (Refines new old Rel, with relation and state_relation). A correct witness’s clients are the accepted declarations that must re-prove. evolution reads its result from the history.
Bundles
| Method | Params | Result |
|---|---|---|
bundle.create | exports?, from_aliases?, helpers?, depends?, doc? | {id, created, exports} |
bundle.get | id | The bundle record |
bundle.list | names?, helpers? | One row per bundle: {id, exports, helpers, doc?, depends?, names?} |
In bundle.create, each of exports is {name, id, role?} and must be accepted with that role, and each of from_aliases is an alias name or {alias, name}. Aliases are resolved once, at creation; the result’s exports is a count. In bundle.list, exports and helpers are counts; names: true lists export names, and helpers: true with names includes helpers.
Projects
The records these methods write are described on the store records page. A project reference’s expectation is expect: {revision, generation, policy_version}, all three required: the revision ID or null, and two positive integers, as ref.list returns them.
| Method | Params | Result |
|---|---|---|
binding-map.create | roots?, exports?, from_aliases?, alias_prefix? | {id, created} |
authoring.create | sources, mappings?, notes? | {id, created}, with validation unchecked |
snapshot.create | bindings, authoring?, assets? | {id, created} |
revision.create | after, intent, parents?, base?, evidence?, obligations?, discharged? | {id, created, before} |
revision.show | id | {id, revision, after, references}: the revision, its after-snapshot and the references naming it |
revision.log | id, limit? | The revision and its ancestors, breadth first along parents, each {id, parents, base?, after, intent} |
policy.create | version, publish, adopt, previous?, reset?, waive?, require?, doc?, protect?, review? | {id, created}. Creating a policy adopts it nowhere. |
record.get | kind, id | The record |
record.list | kind, after?, limit? | Sorted record IDs after after |
ref.create | name, policy, actor, token, idempotency_key? | {ref, revision, policy, policy_version, generation, changed} |
ref.list | prefix? | A map from name to {revision, policy, policy_version, generation} |
ref.publish | ref, revision, expect, actor, token, reset?, evidence?, reviews?, idempotency_key? | {ref, revision, previous, generation, policy, policy_version, changed, decision} |
ref.adopt | ref, policy, expect, actor, token, evidence?, reviews?, idempotency_key? | {ref, revision, generation, policy, policy_version, previous_policy, changed, decision} |
ref.log | ref, limit? | The reference’s moves, newest first, each {event, at, actor, generation, revision, policy, previous, decision, reset?} |
kind is one of binding-map, authoring, snapshot, revision, policy, guarantee, merge and review. Every limit is 1 to 10,000, default 100. ref.create needs an operator and a policy of version 1. ref.publish is authorized by the reference’s active policy, which must also admit the revision. ref.adopt is authorized by the active policy too, and the reference’s revision must meet the incoming policy. Both checks run in the same call as the move, and a refusal writes nothing.
Reports, merges and reviews
| Method | Params | Result |
|---|---|---|
revision.report | id | {id, report}: the revision’s change report |
snapshot.diff | after, before? | {id, report}: from before (default: the empty state) to after, nothing cited |
ref.report | ref, generation? | {id, report}: one recorded move (default: the latest) |
merge.create | parents, base, resolve? | {id, created, merge, inherited?}. The base must be a nearest common ancestor. resolve may hold exports, assets, renames and authoring. |
review.create | ref, subject ({revision} or {policy}), decision (approve or reject), actor, token, note?, display? | {id, created, review} |
None of these is a kernel check: they read receipts and witnesses that replay, replace, refine and correct wrote.
Releases
These methods run on the server’s store and on the runtime’s artifacts/ directory; lema release runs the same code on a store it opens itself. They make no native call. artifact names a directory under artifacts/, and every path is absolute. deployment is a deployment configuration file, or for an app artifact’s release its deployment directory.
| Method | Params | Result |
|---|---|---|
release.create | artifact, deployment, bundles?, doc? | {id, created, kind, artifact, binary, closure_objects?, deployment, doc?} |
release.get | id | {id, record, status} |
release.list | none ({}) | One summary row per release, with its status |
release.verify | id, artifact, deployment?, lean? | The summary with directory, bindings (what was re-derived), status and claim |
release.select | id, artifact, deployment | The verification report with selected. The ID must be a release recorded in this store and not withdrawn. |
release.withdraw | id, reason | {release, withdrawn, changed} |
release.supersede | id, by, reason? | {release, by, changed} |
release.deployment | deployment | {sha256}: the configuration’s digest |
A release’s status is {recorded, withdrawn, superseded_by, supersedes, selectable}.
Related
Written against lema-lang at commit 5a94951, 17 Oct 2026.