Know what is running.
And what should be.
Lembos is an internal developer platform built on versioned building blocks. It records the software you have and the shape it should take in every environment, observes what is actually there, and closes the gap between the two.


The Portal, showing the catalog of a sample retailer the platform seeds in development.
What it is
Not only a portal. Not only a catalog.
Lembos is the system that controls how software is deployed, configured and governed. A portal is how people reach it, and a catalog is part of what it knows — neither is the thing itself.
A catalog says
this component exists, and this team owns it.
A pipeline says
this ran, and it exited zero.
Lembos says
this is what should be running here, this is what is, and here is what closes the difference.
The catalog is purely definitional. It holds declarations and never runtime facts. That boundary is what lets one component run a different version in every place it runs, with the per-environment truth living on a runtime instance instead of forcing the catalog to describe every case.
The idea underneath
Every building block is an entity plus immutable revisions
The entity is what everything names. The revision is what a deployment pins. Blueprints, configuration, API contracts, policies and environments all work this way, which is what makes the rest of the platform expressible rather than aspirational.
- Reproducibility
- A published revision cannot change under anything pinned to it, so replaying a deployment a month later produces the same result.
- Divergence on purpose
- Staging a version ahead, a canary stamp on a newer artifact, a region on an older blueprint — environments differing is progressive delivery, not a failure to converge.
- One question, one answer
- “Which version is in effect here” means the same thing whether the block is a blueprint, a configuration, an API contract, a policy or a workload declaration.
platform/helm-web-service
Blueprint · Helm
- 2.5.0-rc.1Draft
- 2.4.0currentPublished
- 2.3.0Withdrawn
- 2.2.0Deprecated
pinned digest bd0c1a09b788bca1e93c18ae5b04aa86cdceb202
One status machine across every versioned thing. Draft is part of it, so everything has somewhere to sit before it is live — and a version whose artifact cannot be fetched is never handed out.
Convergence
Lembos converges rather than merely deploys
Recording current state alone answers “what is running” but not “is that what we asked for” — which is precisely the question when a configuration was published and never deployed, a rollout half-completed, or someone edited a cluster by hand.
Desired state
What was declared and published
- artifact
- cart-service@sha256:9f2c…
- blueprint
- helm-web-service 2.4.0
- config
- revision 17
- replicas
- 6
Observed state
What the execution target reports
- artifact
- cart-service@sha256:9f2c…
- blueprint
- helm-web-service 2.2.0
- config
- revision 15
- replicas
- 6
Every building block records both what should be running and what is. The difference between the two is drift, and closing it is the work. Automated deployment is one way to close it. Reconciliation, rollback and progressive rollout are others.
The model
Five modules, each an invariant boundary
Aggregates inside a module enforce rules over each other. Anything across a boundary is referenced rather than navigated to. Read them in order: what software exists, what it is delivered with, how it gets there, whether it may, and who is involved.
Catalog
What software exists, and how is it related?
Infrastructure
What is it delivered with?
Delivery
How does a declaration become running software?
Governance
Should this happen?
Organization
Who is involved, and what may they do?
The whole model
Aggregates, lifecycles, behaviours and the events they raise — documented per module and kept current with the code.
Typed by contract, not by label
A component or resource declares the blueprint that defines it, so “what is this thing” resolves to a shape the platform can act on rather than a string someone typed. What each entity provides, consumes and depends on is held as references, so the graph can be traversed without loading half the catalog.


Capabilities
What the platform carries
Each of these is a feature of the model rather than an integration sitting beside it.
Software catalog
Business domains nest into a validated ladder; systems group the components, APIs and resources that form a capability. Purely definitional — declarations, never runtime facts.
Configuration management
Immutable, content-hashed revisions pinned per runtime instance, layered system → component → environment → stamp. Secrets referenced by vault path, never carried.
Infrastructure orchestration
Blueprints pin their provisioner and source, and are only offered once confirmed fetchable. A version that cannot be retrieved is never handed out and then failed on.
Environments and stamps
An environment subdivides into stamps — per country for residency, per region for latency — and the workload declares how many it occupies. Ephemeral ones carry a lease and expire.
Progressive delivery
Traffic weights, analysis windows and abort thresholds are blueprint parameters, not control-plane assertions. A promotion names a stamp scope, so a geographic wave is an ordered sequence.
Rollback as its own transition
A rollback is a distinct kind of event from deploying an older artifact, because policy has to tell them apart — a rollback frequently bypasses gates a forward deployment must pass.
Release provenance
A release freezes its contents when it is ready and records every promotion, so “in which environments was this version tested before production?” has an answer.
Policy that can be reconstructed
An evaluation pins the exact policy version it enforced, so a later edit cannot silently rewrite what was applied. Policy is evaluated before dispatch, not audited after it lands.
Audit by construction
Every domain event is persisted as an audit entry unconditionally, whether or not anything reacts to it. The trail is a property of the model, not a feature bolted beside it.
Feature by feature, each mapped to the module that carries it — What Lembos does.
Guardrails
Access control is three layers, not one
Each answers a different question, and collapsing them into one mechanism fails whichever mechanism is chosen. RBAC alone cannot express “production is restricted to a few people while anyone may create a dev environment”.
- 01
Permission
May this principal do this class of thing?
Flat RBAC, carried as claims. Cheap, and invertible — “who may deploy” is a role query.
- 02
Ownership
Do they reach this particular entity?
Group membership, inherited down the hierarchy, so a member of a parent group reaches what its children own.
- 03
Policy
Is this specific intent allowed right now?
Conditions on facts, evaluated at the moment of the request against a pinned policy version.
And work only routes where it can run
Execution targets declare capabilities, and intent is matched against them before anything is dispatched. Adding a runtime surface means adding a target, not changing orchestration logic.
platform/aws-production
eligiblehardened-runtimebackup-enabledpci-dssplatform/aws-nonproduction
not eligibleno capabilities declared
How it is used
Three people, one system of record
Lembos is adopted by a whole engineering organisation rather than by one team, because the three questions below are usually answered by three different systems that disagree with each other.
A developer
“I need this service running in staging.”
Declares the component against a blueprint and names where it belongs. The configuration layers resolve, policy is evaluated, and the work is dispatched.
Because The blueprint already carries the chart, the traffic weights and the dashboards — none of the runtime has to be learned to use it.
A platform engineer
“I need to change how every service is deployed.”
Publishes a new blueprint version. Nothing pinned to the old one moves until its owner moves it, and where each version is in force stays visible.
Because Versions are immutable and pinned, so the golden path can change without a synchronised migration across every team at once.
Security and compliance
“Show me what was running in production in March.”
Reads the release, the promotions that carried it, and the policy version that was evaluated at the time.
Because Every domain event is persisted as an audit entry unconditionally, and an evaluation pins the exact policy version it enforced.
What that looks like in practice
A review environment that cleans itself up
Ephemeral environments carry a lease and a TTL, so a pull-request environment expires on its own instead of accruing cost until someone notices.
A payment provider that differs per country
A stamp-layer override, not a reason to fork the component or duplicate the environment. The narrowest layer wins and the rest is shared.
A regulated workload that cannot land anywhere
The component requires a capability; only execution targets declaring it are eligible. Policy is evaluated before dispatch, not audited after it lands.
Germany before France, with a look in between
A promotion names a stamp scope, so a geographic wave is an ordered sequence of promotions with a human able to check between them.
What you operate
A platform you run yourself
There is no hosted Lembos. It is one .NET solution composed by Aspire — an orchestrator behind a single GraphQL endpoint, an identity server, a worker running durable workflows, and the Portal — provisioning into execution targets you own.
.NET 10
Every service
Aspire
Composition and local run
HotChocolate
The GraphQL surface
Temporal
Durable workflows
PostgreSQL
Persistence, via EF Core
OpenIddict
Identity and tokens
Blazor + MudBlazor
The Portal
YARP
The gateway
OpenTelemetry
Traces, metrics, logs
Redis
Cache and subscriptions
Running it today means running the solution itself — the repository covers that. A packaged install, the chart that turns this into a platform your organisation operates, is still ahead of it, and the configuration is already shaped for it.
The reasoning is in the open too
Decision records state why the architecture is the way it is, one document per decision. Enhancement proposals hold the changes not yet decided. Both are in the repository, and both take comments.
Questions, or interested in contributing? [email protected]