LemmaBase
@org/repo is part of the Lemma language. The engine parses it, plans against it, and reports Error::Registry for it. That means the engine must know which registry a qualifier names. Registries live in the engine (engine/src/registry.rs). Hosts never invent URLs, status mappings, or error text.
Today every @org/repo names LemmaBase, bound to https://lemmabase.com. That binding is not configurable: no argument, no environment variable, no debug/release split. A future registry is a new identifier form in the language plus a new engine-side Registry implementation; never a retargeted LemmaBase.
The engine performs no I/O. It emits Fetch requests and consumes HttpResponse values. The socket is always the host's HTTP stack, so JVM trust stores and proxy properties, Erlang application configuration, browser settings, Node CA / dispatcher config, and CLI system proxies all apply.
You can run entirely offline if every @ repository is already available as source (for example under lemma_deps/).
Resolve first, then load
Engine never auto-fetches on load or run. Every external @ reference must be resolved into source text first, then loaded.
Sans-IO protocol (engine):
Registries::default()— catalogue; today LemmaBase onlyregistry_for(qualifier)— which registry owns an@…nameInstall— one repository download (start/respond/run)Resolve— transitive missing@references (start/respond/run)HttpTransport— sync driver for Rust hosts (get(&Fetch))
Hosts loop: receive Fetch (URL + request headers), perform GET, hand back HttpResponse (status + response headers + body) or TransportFailure.
How you resolve depends on how you run Lemma:
- CLI:
lemma install --all(orlemma install @owner/repo) downloads from LemmaBase and writeslemma_deps/. Other commands read workspace.lemmafiles plus that cache. Commitlemma_deps; there is no lock file. - Rust embedders: implement
HttpTransport, thenInstall::run/Resolve::runwithRegistries::default(), or drive the step machines yourself. Load returned source withSourceType::Dependency. - npm / Hex / Maven: call
install(download only; no load, nolemma_deps/write), thenloadwith the returned id as the source label before loading workspace specs.
If you load a spec while some @ references are still unresolved, planning reports those as missing.
Resolving repositories from Rust
use lemma::{Engine, HttpTransport, Registries, Resolve, ResourceLimits, SourceType};
use std::collections::HashMap;
use std::sync::Arc;
let registries = Registries::default();
let transport = /* your HttpTransport */;
let mut context = lemma::Context::new();
let mut sources = HashMap::new();
// ... insert local workspace specs into `context`, mirror text in `sources` ...
Resolve::run(
®istries,
&mut context,
&mut sources,
&ResourceLimits::default(),
&transport,
)?;
let mut engine = Engine::new();
let batch: Vec<(SourceType, String)> = sources
.into_iter()
.map(|(path, code)| (SourceType::Path(Arc::new(path)), code))
.collect();
engine.load(batch)?;
Single repository:
use lemma::{Install, Registries};
let registries = Registries::default();
let result = Install::run(®istries, "@iso/countries", &transport)?;
// result.source, result.id
Per-host transports
| Host | Socket | Corporate configuration |
|---|---|---|
CLI / Rust ReqwestTransport |
reqwest (rustls + system-proxy) |
HTTPS_PROXY / HTTP_PROXY / NO_PROXY, OS trust store |
| npm | host fetch (wasm binding) |
browser settings; Node NODE_EXTRA_CA_CERTS, undici dispatchers |
| Maven | java.net.http.HttpClient (default or injected) |
javax.net.ssl.trustStore, http.proxyHost, java.net.useSystemProxies, custom SSLContext |
| Hex | Lemma.Transport.get/2 (Req) or injected fun |
application Req / Finch / cert config |
| LSP | no fetch; hover uses navigation_url |
n/a |
Hosts forward Fetch.headers on the request and return response headers. LemmaBase sends no headers today.
Private host source
You can still load source you obtained yourself with @owner/name labels:
engine.load([(
SourceType::Dependency("@myorg/rules".to_string()),
my_source_text,
)])?;
There is no authentication in the public LemmaBase API yet; request headers exist so a future private registry can send Authorization.
Bundle requirements
A bundle is ordinary Lemma source. A published LemmaBase bundle opens with a repo line whose name matches the repository id, for example repo @iso/countries. That @ name is assigned when published. Installed repositories stay isolated: a LemmaBase repository never merges with your workspace or another installed repository, and every spec in a repository must come from the same place.
Within a bundle, spec names are normal identifiers (spec billing). Cross-repository imports use @, as in uses rates: @acme/finance rates. Unqualified uses x: rates only looks inside the same repository. In workspace files, declare local repos without @ (repo finance).
The resolver keeps fetching unresolved references until everything is satisfied. One .lemma response per identifier is enough.
Adding a registry later
- New identifier form in the language /
RepositoryQualifier. - New
impl Registryin the engine (fetch_for,bundle_from,navigation_url). - New arm in
Registries::registry_for(and optionally host-constructed config onRegistries).
Hosts keep answering Fetch with GET. A non-HTTP protocol adds a new exhaustive InstallStep / ResolveStep variant; every host must handle the new tag (Rust fails to compile; Java/Elixir raise).