Sketch aggregates, events, and bounded contexts. In Protean that model is the architecture, and everything else, the API, the docs, the contracts, is derived from it. And because the model has rules the framework checks, it is a safe target for an AI to generate and act against.
@domain.aggregate class Order: customer_id: Identifier(required=True) status: String(max_length=20, default="draft") items = HasMany("OrderItem") @invariant.post def must_have_items_when_placed(self): if self.status != "draft" and not self.items: raise ValidationError(...) # rejected at construction. invalid state cannot exist. Order(customer_id="c-1", status="confirmed") ValidationError: Order must have at least one item
All four come from one idea: the model is the source of truth, trustworthy enough to build everything else on.
Protean parses your model into a machine-readable Intermediate Representation. Docs, API specs, and contracts are derived from it, so they cannot drift from the code.
Domain objects are always valid, or they do not exist. Four layers of validation run on every change, and the structure is checked before the first request.
Start with plain domain-driven design. Add CQRS or event sourcing for one aggregate at a time, in the same codebase, with no rewrite.
Your domain knows nothing about databases, brokers, or caches. You swap them in configuration, and the model, the tests, and the rules stay untouched.
A real Protean domain, running on Pyodide in this page. Press check and Protean reads the design back: what each aggregate enforces, what it is missing, why it matters, and how to fix it. The code is editable, and nothing leaves your browser.
Order has no pre/post invariants (own or
inherited); it enforces no business rules and may be an anemic data holder.@invariant.pre or
@invariant.post methods expressing the business rules the aggregate must
always satisfy, or reconsider whether this concept is an aggregate at all.Order has no command handler, no write
path existsFirst check downloads the Python runtime, about 8 MB over the wire, then it is cached by the browser.
Add a field to an Order in most stacks and you touch it in nine places: the model, the migration, the schema, the spec, the client types, the docs, the fixtures, the event, the version.
In Protean you touch the model. Everything else follows from it, so nothing drifts from the drawing.
Your domain model does not change. Protean moves the seams, from in-process calls to a message broker, through configuration, so the deployment shape becomes a setting you choose.
Every external concern sits behind a port. Choose an adapter, or write one, and Protean wires it into your domain.
A domain model is a small, rule-bound artifact, which is what a machine needs to work against safely. Protean gives an AI a model to generate from, a boundary to act through, and a history it cannot rewrite.
An AI proposes a model, Protean validates it at startup and says what is wrong, and the AI corrects what the framework rejects.
Every change goes through a command that must satisfy your invariants. An AI behind that boundary cannot do what the rules forbid.
Turn on event sourcing and every change becomes a recorded fact, so what an AI decided, and when, is auditable and replayable.
A subscriber wraps an existing system as an anti-corruption layer, so AI modernizes it one piece at a time, with the core intact.
One source of truth, an always-valid domain, and why both matter more now that machines write the code.
Built for backend systems whose hard part is the business rules and the states things move through. It is the wrong fit for raw speed, very high data volume, or table-first apps. Is Protean for you?
About twenty minutes from install to a running, event-driven domain, with no infrastructure decisions to make first.