The Modern Python Framework

the python framework for ai products.

agents, llms, rag, and mcp — wired together, no glue code.

$ pip install lexigram
HOOKagents · llms · rag · mcp · memory
COREweb · sql · cache · auth · queue · events
TRUSTdi · contracts · modules · async
lexigram-ai-agents · react execution● Live
agent.py
# wire the agent in one module
from lexigram.ai.agents import AgentsModule, AgentBase

@tool
async def search_docs(q: str) -> str:
    ...

class ResearchAgent(AgentBase):
    system_prompt = "research"
    tools = [search_docs]
    strategy = "react"
User Prompt"Explain the Result pattern"
ReAct · Iteration 1Thought: I should search the docs first.
Tool · @toolsearch_docs("Result pattern")
Injected
Result · Ok(str)"The Result pattern makes failure explicit..."

↑ a fully wired async agent — zero glue code

lexigram-ai-agents

agents,
wired together.

Define an agent, decorate a few @tool methods, pick a strategy. The container resolves the llm, the tools, and the session scopes — you just run it.

base classes

subclass AgentBase, set a prompt, ship.

strategies

react, plan-and-execute, supervisor — swap freely.

@tool decorator

turn any async function into an agent tool.

wired through DI

vector stores, services, sessions — all injected.

Strategy

ReAct Executor

Agent Core

Data Analyst Agent

Injected Tool

Postgres Query Engine

the whole backend, ready when you are.

Type-safe end to end. Zero globals. Async at every layer. The patterns that hold up at 100k lines start working on line one.

type-safe to the edges.

Full container inference. Your IDE knows what exists, what's wired, and what's missing — no guessing, no surprises.

IDE auto-completion active

async, end to end.

Container, modules, controllers — concurrency-safe by construction. Not an add-on, the foundation.

lifecycle you trust.

Providers boot in priority order. Shutdown is clean. Resources never leak.

one unified ecosystem.

Web, AI, SQL, events, tasks, auth, cache, search — all wired through one container, all built around one rule. Pick a few, ship the thing.

a small core, a wide family.

Every package talks through contracts. Mix the ones you need; the rest stay out of your way.

lexigram-web

async routing and controllers, DI-native.

lexigram-ai

agents, llms, rag, mcp — one entry point.

lexigram-sql

sqlalchemy sessions and unit-of-work.

lexigram-search

full-text and vector search, one contract.

lexigram-auth

JWT, OAuth, and policies — wired in.

lexigram-events

event bus over your broker of choice.

v0.1 · early on purpose

early on purpose.

Lexigram is in 0.1 — which means you can still change it. APIs may shift before 1.0, so pin your versions, and tell us what feels wrong. Shaping a framework is more fun when it's still soft.

why it grows with you.

The patterns that get you to a working demo on Sunday are the same patterns that still hold up at 100k lines. Declare what you need; the container resolves the rest.

wiring by hand

Couplings hide everywhere; small changes ripple.

service = UserService(
    PostgresRepo(),
    RedisCache(),
    EmailClient(
        smtp_host="localhost"
    )
) # ❌ Brittle at scale
  • Dependencies spread across the codebase
  • Hidden coupling between components
  • A change in one place breaks another

wired through DI

Say what you need. The container does the rest.

class UserService:
def __init__(
self,
repo: UserRepository,
cache: Cache
): ...

# ✅ Container resolves it
service = await container.resolve(UserService)
  • Contracts, never implementations
  • Type-safe end to end
  • Swapping an implementation is one line

the moving parts.

Lexigram revolves around one container and a handful of well-named seams. Once you know them, the rest fits.

example.py

where bindings live

class DatabaseProvider(Provider):
    name = "database"
    priority = ProviderPriority.INFRASTRUCTURE

    async def register(self, container: ContainerRegistrarProtocol) -> None:
        container.singleton(DatabaseProtocol, PostgresDatabase)

    async def boot(self, container: BootContainerProtocol) -> None:
        db = await container.resolve(DatabaseProtocol)
        await db.connect()

ship something this weekend.

Two installs and a dozen lines. Boot the app, hit the route, watch it work.

$ pip install lexigram lexigram-web
main.py
from lexigram import Application
from lexigram.web import WebProvider

app = Application(name="hello")
app.add_provider(WebProvider())

@app.controller()
class HelloController:
@get("/hello")
async def hello(self) -> dict:
return {"message": "Hello, Lexigram"}

if __name__ == "__main__":
app.run()
Join the Community

Build with
Lexigram

Whether you're moving a legacy monolith toward something cleaner or starting fresh on a weekend project, we'd love to hear from you. Sign up for early access, framework updates, or enterprise support.

Email
hello@lexigram.dev
Location
Building globally

We typically respond within 24 hours.