An ASGI web framework with dependency injection, metadata-driven routing, and modular architecture.
Project description
lauren
lauren framework: a metadata-first Python web framework. NestJS-style modules, Axum-style extractors, FastAPI-class ergonomics — resolved into an immutable execution graph at startup.
Documentation: https://lauren-py.dev
Source Code: https://github.com/lauren-framework/lauren-framework
For AI Agents & Coding Assistants
Install all skills in one command
# Claude Code, Cursor, Copilot, Continue, Codex CLI — auto-detected
npx skills add lauren-framework/lauren-framework
This copies all 60+ SKILL.md context packs into your agent's global skills
directory (~/.claude/skills/, ~/.cursor/skills/, etc.). The next time your
agent opens a Lauren project it has pre-loaded expertise on auth, database,
API patterns, observability, security, and more.
| Resource | What it contains |
|---|---|
llms.txt |
2 KB framework overview — start here |
lauren/llms-full.txt |
25 KB complete reference — all APIs, patterns, common errors |
AGENTS.md |
Agent rules, by-task lookup, file ownership, common errors, definition of done |
CLAUDE.md |
Conventions, commands, golden rules, pattern selection guide |
skills/ |
60+ copy-paste skill guides covering every common task |
Full install guide and skills index: docs/guides/agent-skills.md
lauren is a modern, high-performance Python web framework for building APIs that need to fail at startup, not in production. It is built on these core ideas:
- Metadata-first. Routes, dependency-injection bindings, module boundaries, lifecycle hooks, middleware, and guards are declared with decorators that attach metadata. They never rewrite your functions.
- Startup-validated, runtime-pure. Every misuse — circular DI, missing
module export, malformed extractor, conflicting routes — is rejected
inside
LaurenFactory.create(...), not on the first request. - No reflection on the request path. The whole graph is compiled into immutable structures at startup; serving a request is pure traversal.
- AI-ready by default. Public surface is mirrored in
llms.txt/llms-full.txtand exported in__all__— a CI hook keeps the two in lock-step.
Features
- Fast — Zero per-request reflection: routes, DI graph, extractors, and middleware are fully compiled at startup.
- Implicit extractors — Path params, query strings, and JSON bodies are
auto-detected from type annotations. Write
id: int,q: str,body: MyModelwithout boilerplate unless you need the explicit form. - Three-scope DI —
SINGLETON,REQUEST, andTRANSIENTscopes with Protocol bindings, multi-bindings (list[T]), and NestJS-style custom providers (use_value/use_class/use_factory/use_existing). - Pipes — Post-extraction value transforms: validate, coerce, or enrich parameters before they reach the handler. Function-based, class-based, chainable, and DI-aware.
- Guards, Middleware & Interceptors — All three attachment points. Guards run first (allow/deny); middleware wraps raw request/response bytes; interceptors wrap handler execution for timing, caching, and response transforms.
- WebSockets — First-class
@ws_controllergateways with typed Pydantic frames, discriminated-union dispatch, andBroadcastGrouprooms. - Server-Sent Events —
EventStreamwith keep-alive heartbeats andLast-Event-IDresumability for AI token-streaming patterns. - Typed streaming —
StreamingResponse[T]auto-negotiates between SSE, NDJSON, and JSON Lines based on the client'sAcceptheader. - Background tasks —
BackgroundTasksextractor fires work after the response is sent.TaskHandleexposes cancel/await. Signals notify on start, complete, and failure. - Static files —
StaticFilesModule.for_root("/assets", directory="./public")with ETag caching,Cache-Control, and path-traversal protection. - Socket.IO — Engine.IO v4 / Socket.IO v5 adapter via
@socketio_controller. - OpenAPI 3.1 — Automatic schema generation from Pydantic models and route decorators. Swagger UI and ReDoc served out of the box.
- Lifecycle signals —
SignalBuswithStartupBegin,StartupComplete,ShutdownBegin,RequestReceived,RequestComplete, and more. - Standards-based — Built on ASGI, Pydantic, and anyio.
Requirements
Python 3.11, 3.12, 3.13, and 3.14 are supported. Hard dependencies:
- Pydantic — request validation and response serialisation.
- anyio — async backend and thread-pool offload for sync handlers.
Installation
pip install lauren
# with an ASGI server:
pip install "uvicorn[standard]"
# or granian (faster on CPython):
pip install granian
Quick start
from pydantic import BaseModel
from lauren import LaurenFactory, controller, get, post, module, use_guards
from lauren.types import ExecutionContext
class CreateUser(BaseModel):
name: str
age: int
class AdminGuard:
async def can_activate(self, ctx: ExecutionContext) -> bool:
return ctx.request.headers.get("x-role") == "admin"
@controller("/users", tags=["users"])
class UserController:
@get("/{id}")
async def get_user(self, id: int) -> dict:
return {"id": id, "found": True}
@post("/")
async def create(self, body: CreateUser):
return body.model_dump(), 201
@get("/admin")
@use_guards(AdminGuard)
async def admin_only(self) -> dict:
return {"access": "granted"}
@module(controllers=[UserController])
class AppModule:
pass
app = LaurenFactory.create(AppModule, docs_url="/docs")
uvicorn main:app --reload
# → http://127.0.0.1:8000/docs (Swagger UI)
Dependency injection
from lauren import injectable, post_construct, pre_destruct, Scope
@injectable(scope=Scope.SINGLETON)
class UserRepository:
@post_construct
async def warm(self) -> None:
self.cache: dict[int, str] = {}
@pre_destruct
async def flush(self) -> None:
self.cache.clear()
async def find(self, user_id: int) -> str | None:
return self.cache.get(user_id)
async def upsert(self, user_id: int, name: str) -> None:
self.cache[user_id] = name
@controller("/users")
class UserController:
def __init__(self, repo: UserRepository) -> None:
self.repo = repo
@get("/{id}")
async def get_user(self, id: int) -> dict:
name = await self.repo.find(id)
if name is None:
return {"id": id, "found": False}, 404
return {"id": id, "name": name}
@module(providers=[UserRepository], controllers=[UserController])
class AppModule:
pass
Modules
Modules are the unit of feature composition. Each module declares what it provides, what it exports, and what it imports from other modules — similar to NestJS:
@module(
imports=[DatabaseModule, AuthModule],
controllers=[UserController, ProfileController],
providers=[UserService, EmailService],
exports=[UserService],
)
class UsersModule:
pass
Circular dependency detection, missing export errors, and scope violations are all caught at startup — before your first request.
SSE / streaming
from lauren import EventStream, ServerSentEvent, get
@get("/events")
async def stream(self) -> EventStream:
async def generate():
for i in range(10):
yield ServerSentEvent(data=f"tick {i}", event="tick")
await asyncio.sleep(1)
yield ServerSentEvent(data="done", event="close")
return EventStream(generate(), keep_alive=15.0)
For typed, content-negotiated streams (SSE / NDJSON / JSON Lines):
from pydantic import BaseModel
from lauren import StreamingResponse
class Tick(BaseModel):
seq: int
@get("/ticks")
async def ticks(self) -> StreamingResponse[Tick]:
async def gen():
for i in range(100):
yield Tick(seq=i)
await asyncio.sleep(0.05)
return StreamingResponse(gen())
Static files
from lauren.static_files import StaticFilesModule
@module(imports=[StaticFilesModule.for_root("/assets", directory="./public")])
class AppModule:
pass
Or mount any ASGI sub-app:
app = LaurenFactory.create(AppModule)
app.mount("/static", StaticFiles(directory="static"))
Performance
Runtime is pure traversal of pre-compiled structures — no
inspect.signature(...), no get_type_hints(...), no isinstance(...)
walking on the hot path. The DI graph, route table, extractor bindings, and
middleware pipeline are all resolved once at startup. Each request pays only
the cost of dispatching through the already-compiled graph.
Optional dependencies
| Package | Purpose |
|---|---|
uvicorn / hypercorn / granian |
ASGI server (none bundled — pick one) |
httpx |
Required for lauren.testing.TestClient |
orjson |
Faster JSON — auto-detected at import time |
msgspec |
Alternative fast JSON encoder via MsgspecEncoder |
python-multipart |
Required for Form[...] extractors |
Companion packages
| Package | Purpose |
|---|---|
lauren-middlewares |
CORS, rate-limit, GZip, security headers, request-id, trusted hosts, HTTPS redirect, body-size limit, timeout |
lauren-logging |
Structured logging module with processor pipeline, contextvars binding, pluggable backends (stdlib, structlog, file, fan-out) |
lauren-guards |
Auth guards: JWT bearer, API key, basic auth, OAuth2 introspection, session cookie, RBAC/ABAC, CSRF, IP allowlist |
Deployment
lauren is a standard ASGI application — deploy exactly like FastAPI or Starlette:
# Uvicorn
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
# Granian (Rust-based, faster on CPython)
granian --interface asgi main:app --host 0.0.0.0 --port 8000
# Hypercorn (HTTP/2 + HTTP/3)
hypercorn main:app --bind 0.0.0.0:8000
Contributing
We welcome contributions of every size, from typo fixes to whole subsystems. Read first:
CONTRIBUTING.md— setup, branch & commit conventions, and the quality bar.AGENTS.md— the design invariants every PR must respect, whether the author is human or an AI agent.
uv tool install prek # one-time
prek install # wires up the git hook
nox # lint + tests + typecheck
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lauren-1.0.0.tar.gz.
File metadata
- Download URL: lauren-1.0.0.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0839576669b7ff86070e11c64bc4ef564add82ee5cf7da77cdfcca3dce734f2
|
|
| MD5 |
6b6924afb928242d71951055c0f90431
|
|
| BLAKE2b-256 |
0a9dac410c022f6ee2f701fd0a514a8affc28edb80ceddab2b16edeeda1f8010
|
Provenance
The following attestation bundles were made for lauren-1.0.0.tar.gz:
Publisher:
release.yml on lauren-framework/lauren-framework
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lauren-1.0.0.tar.gz -
Subject digest:
f0839576669b7ff86070e11c64bc4ef564add82ee5cf7da77cdfcca3dce734f2 - Sigstore transparency entry: 1475783613
- Sigstore integration time:
-
Permalink:
lauren-framework/lauren-framework@c411d32289b400d3172cf87430167e73b768531c -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/lauren-framework
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c411d32289b400d3172cf87430167e73b768531c -
Trigger Event:
push
-
Statement type:
File details
Details for the file lauren-1.0.0-py3-none-any.whl.
File metadata
- Download URL: lauren-1.0.0-py3-none-any.whl
- Upload date:
- Size: 249.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
091cb0ce04e7c7e066fef3703adcd694c56cab6b4cafe13a81b7b503e5bb0823
|
|
| MD5 |
3379fbb9388353426071bfc202e1055a
|
|
| BLAKE2b-256 |
cb43a214b1203be110485967df0c61014392e9ded02a10018b3b47414290bb46
|
Provenance
The following attestation bundles were made for lauren-1.0.0-py3-none-any.whl:
Publisher:
release.yml on lauren-framework/lauren-framework
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lauren-1.0.0-py3-none-any.whl -
Subject digest:
091cb0ce04e7c7e066fef3703adcd694c56cab6b4cafe13a81b7b503e5bb0823 - Sigstore transparency entry: 1475783821
- Sigstore integration time:
-
Permalink:
lauren-framework/lauren-framework@c411d32289b400d3172cf87430167e73b768531c -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/lauren-framework
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c411d32289b400d3172cf87430167e73b768531c -
Trigger Event:
push
-
Statement type: