Name a set of objects with a bundle
Record a set of accepted objects under export names once, then receive them all in a draft as Received bindings.
A bundle (lema.bundle/v1) maps export names to exact object IDs and roles. It is a store record, not an object, so creating one changes no ID. A draft that receives a bundle builds exactly the objects it would build with the same bindings written by hand. The example below is the one crates/lema-cli/tests/bundles.rs runs: two bundles received by lean/std/MapClient.lean.
Before you start
- A running server on a store where the objects to export are accepted. Here that is Core v2, with the aliases
core.Prog,core.Prog.call,core.Prog.retandcore.Safe, andlean/std/Map.lean. - You know how
Received.*bindings work inelaborate(Reuse a proof by identity). - In the commands,
$SOCKis the server’s socket. Values in angle brackets are placeholders.
Steps
-
Create a bundle from aliases. Each alias is resolved once, now, to the ID it names, so later moves of the alias do not change the bundle:
core-bundle.json {"from_aliases": [ {"alias": "core.Prog", "name": "Prog"}, {"alias": "core.Prog.call", "name": "Prog.call"}, {"alias": "core.Prog.ret", "name": "Prog.ret"}, {"alias": "core.Safe", "name": "Safe"}], "doc": "Core v2 programs and their safety."}Shell lema --socket $SOCK call bundle.create --params-file core-bundle.jsonThe response is
{id, created, exports}. A plain alias name infrom_aliases, instead of an object, exports the alias under its own name. -
Create a bundle from IDs. List
exportsas{name, id, role?}. Here each entry is a name’s{id, role?}from Map’snamesmap, withnameadded. A declaration is exported by its plain ID. A structure or inductive type needs one of its roles (type,ctor,ctor:i,field:i,generated:rec). The Map bundle exportsOrder,MapOp,MapOp.insert,MapOp.toList,MapReply,contract,Sorted,find,update_selfandupdate_other:map-bundle.json {"exports": [<ten entries, each {name, id, role?}>], "helpers": ["update_self", "update_other"], "depends": ["<core bundle id>"], "doc": "Std.Map: the finite map contract and its lemmas."}helpersare left out ofbundle.list’s names unless you ask for them. They are received like any other export.dependsrecords the bundles this one re-exports from. Receiving a bundle does not receive its dependencies.- Export names are dotted identifiers that Lean parses without escapes, and without
?or!. That is whyfind?is exported asfind.
Sending the same exports again, in any order, returns the same
idwithcreated: false. -
Inspect the bundles:
Shell lema --socket $SOCK call bundle.get --params '{"id": "<core bundle id>"}' lema --socket $SOCK call bundle.list --params '{"names": true}'bundle.getreturns the record.bundle.listreturns one row per bundle,{id, exports, helpers, doc?, depends?, names?}, whereexportsandhelpersare counts.names: trueadds the export names, andhelpers: truewith it adds the helpers too. -
Receive the bundles in
elaborate, or inpublishto accept the draft in the same call. Each exportNbecomes the bindingReceived.N, orReceived.<as>.Nwhen the receive givesas.renamemaps an export name to another local name. MapClient uses names such asReceived.callandReceived.mapInsert, so it renames:client.json {"source": "<text of lean/std/MapClient.lean>", "prefix": "LemaDraft", "seed_salt": "lean/std/MapClient", "receive": [ {"bundle": "<core bundle id>", "rename": {"Prog.call": "call", "Prog.ret": "ret"}}, {"bundle": "<map bundle id>", "rename": {"MapOp.insert": "mapInsert", "MapOp.toList": "mapToList", "contract": "mapContract", "find": "mapFind", "update_self": "updateSelf", "update_other": "updateOther"}}]}Shell lema --socket $SOCK call publish --params-file client.jsonYou can mix
receivewith explicitbindings. Withreceive, the response addsreceived_bundles, the sorted IDs of the bundles received, so a consumer can pin them. With{"bundle": "<core bundle id>", "as": "Core"}instead, the bindings would beReceived.Core.Prog,Received.Core.Safeand so on.
A receive binds every export and installs the closure of all of them, so keep each bundle to what its consumers need. Json’s laws, for example, are a bundle of their own.
Refusals
All of these are refused before any native call:
| Message contains | Cause |
|---|---|
Received.Prog is bound twice: by … | Two receives, or a receive and an explicit binding, give the same name. Use as or rename. |
unknown bundle | No bundle with that ID in this store. |
has no role | An export or binding names a role its object does not have. |
dotted identifier Lean parses | An export name or as that Lean would not parse, such as aλb. |
is not accepted in this store | An export names an object this store has not accepted. |
the bundle … exports no such name | A rename key that is not one of the bundle’s exports. |
Written against lema-lang at commit 5a94951, 17 Oct 2026.