Architecture overviewο
Status: π΄ DA REVISIONARE
This page explains how genro-asgi is put together and the principles behind it.
It is explanation, not a how-to: read it to understand why the pieces are
shaped the way they are. The normative source is
SPECIFICATION.md
(the decision log, D1β¦); this page summarizes it and never contradicts it.
Core principlesο
These are the guiding principles of the redesign (SPECIFICATION.md Β§1). They explain most of the design decisions you will meet in the code.
No globals. The server is an instance with its own state β no module-level variables, no singletons.
del servergarbage-collects everything it owns. State lives in objects, connected by semantic parent references.Config is data, not structure. What a server is comes from a configuration recipe rendered onto it; the code shape does not change with the deployment.
Objects always exist; backends come from config. There is no
X | Noneattribute flipped on by a flag. The session store, the auth core, the task manager are always there β their backend is what configuration selects.Work at the time of use. Expensive machinery (the thread pool, the task manager) is provisioned lazily, on first use.
Routes are static from boot. The routing tree is built once; routing is never used as a mutable registry.
Extension by subclassing; capabilities as mixins. You add behaviour by subclassing an application, and the server composes capabilities (auth, session, tasksβ¦) as mixins over a base.
The request flowο
uvicorn
β AsgiServer the server IS the ASGI app
β middleware chain errors β cors β auth β session (ordered)
β demultiplex first path segment β mount, else primary
β application a RoutedApplication (or a subclass)
β @route handler(**params)
β Response buffered, or a StreamingResponse
β ASGI send
Middleware order is a number, not a class trait: the chain sorts by it, smaller
is more outer. Only errors is on by default; session and auth are armed by
their mixins when you configure them.
The two layers: server and applicationο
genro-asgi separates what the server owns from what an application does.
BaseServerο
BaseServer is the common substrate of every server (SPECIFICATION.md Β§4, D2).
It owns: one uvicorn loop, one monitored thread pool for blocking work, the
primary application (always present, answers / and everything no mount
claims), the secondary mounts (a dict of apps keyed by URL prefix), the
lifespan (ordered startup/shutdown), and the request registry. At the base,
authenticate() and session() answer βnobody / noneβ β auth and sessions are
capabilities layered on top, not built into the base.
The one dispatch rule (D3) is: first path segment β a secondary mount if one claims it, otherwise the primary app. A single-app server is just a base server used with only its primary β there is no separate mechanism.
AsgiServerο
AsgiServer is the shipped composition (D22): it stacks every capability mixin
over BaseServer in one MRO β communication, auth, session, middleware,
plugins, storage, tasks. This is the complete mono-process async server. You
turn a capability on through a constructor kwarg (auth=β¦, middleware=β¦,
tasks=β¦, plugins=β¦); the mixin peels the kwargs it understands and forwards
the rest down the cooperative __init__ chain.
Because auth is a mixin and not part of the base, an internal (non-public)
server can compose the same base without the auth mixin β its auth and
sessions are None by design, and whoever fronts it owns them (D1, D6).
BaseApplication and RoutedApplicationο
BaseApplication is the app-side contract: an ASGI callable with a
mount_name and a server reference assigned once by the owning server at
attach time (a second assignment raises). RoutedApplication wires
genro-routes into it: handlers are
@route-decorated methods, resolved through the appβs own router. The
OpenApiApplication, McpApplication and McpOpenApiApplication subclasses add
protocol faces (OpenAPI/Swagger, MCP) over the same route tree β which is why
one decorated method can serve REST and MCP at once.
The automatic _server applicationο
Every AsgiServer auto-mounts a ServerApplication at /_server (D4). It
exposes the serverβs own management surface β login, users, tokens, tasks β
under /_server/β¦, and its OpenAPI schema at /_server/_meta/schema_json. It
is automatic, not configured: a hand-built server has it exactly like a
config-materialized one.
Where to go nextο
Getting started β install and run.
Concepts β the model in more practical terms.
SPECIFICATION.mdβ the full decision log.