Agents
Define an agent class, decorate a few @tool methods, pick a strategy (react, plan, your own). The container wires the LLM, the tools, and the trace — you just run it.
# wire the agent in one module
from lexigram.ai.agents import AgentsModule, AgentBase
@tool
async def search_docs(query: str) -> str:
...
class ResearchAgent(AgentBase):
system_prompt = "You are a research assistant."
tools = [search_docs]
strategy = "react"
# resolve & run
result = await agent.run("Explain the Result pattern")
return result.unwrap() hey — wanna ship an AI app this weekend?
Lexigram is a python framework that hands you agents, LLMs, RAG, MCP, and memory already wired up — no glue code, no “and then we add the queue,” no 200-line config files. The full async backend is right there too: web, sql, cache, auth, queues, events — all wired through one container, all built around one rule. It’s async-native, container-managed, and built so the same patterns that get you to a demo on Sunday still hold up when the weekend project turns into the company. Pick a few packages, boot the application, ship the thing.
HOOK agents · llms · rag · mcp · memoryCORE web · sql · cache · auth · queue · eventsTRUST di · contracts · modules · asyncAgents
Define an agent class, decorate a few @tool methods, pick a strategy (react, plan, your own). The container wires the LLM, the tools, and the trace — you just run it.
RAG
Stand up a retrieval pipeline with one RAGPipeline(...). Embedders, retrievers, chunkers, and rerankers are all swappable through contracts. Ingest once, answer forever.
MCP
Serve tools to any MCP-compatible host, or consume tools from any MCP server. Same contracts, same container. Your agent doesn’t care which side of the wire it’s on.
# build a rag pipeline in one module
from lexigram.ai.rag import RAGModule, RAGPipeline
pipeline = RAGPipeline(
embedder="text-embedding-3-small",
retriever="qdrant",
top_k=5,
)
await pipeline.ingest(docs)
result = await pipeline.answer("What is the Result pattern?")
return result.unwrap() Say what you need, not who provides it. Contracts live in lexigram-contracts so nothing across the rest of the codebase has to know who’s on the other end.
from typing import Protocol
class NotificationServiceProtocol(Protocol): async def send(self, user_id: str, message: str) -> None: """Send a notification to a user."""Constructor injection, no globals. Your IDE gets full type inference, your tests get whatever fake you want to pass in.
from lexigram import injectable
@injectableclass CheckoutService: def __init__(self, notifier: NotificationServiceProtocol) -> None: self.notifier = notifier
async def complete_order(self, user_id: str) -> None: # Process order... await self.notifier.send(user_id, "Order Complete!")A provider is the seam where “what I need” meets “what to use.” Group your bindings, set a priority, and the container handles the rest.
from lexigram import Provider, ProviderPriority
class NotificationProvider(Provider): name = "notification" priority = ProviderPriority.COMMS
async def register(self, container) -> None: # Bind the concrete implementation to the protocol container.singleton(NotificationServiceProtocol, SlackNotifier)Boot a single Application with the providers you want wired together. That’s the whole backend, ready when you are.
from lexigram import Application
async with Application.boot( name="my-app", providers=[NotificationProvider(), WebProvider()]) as app: # App is fully booted. Infrastructure is ready. pass# one application, every provider wired
from lexigram import Application
from lexigram.web import WebProvider
from lexigram.sql import DatabaseProvider
from lexigram.cache import CacheProvider
from lexigram.ai.llm import LLMProvider
app = Application(name="my-app")
app.add_providers([
DatabaseProvider(),
CacheProvider(),
WebProvider(),
LLMProvider(),
])
await app.start() 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.
→ github.com/lexigram-framework/lexigram/issues
Lexigram is a small core and a wide family of packages — all wired through one container, all built around one rule.
graph TD
subgraph "The Foundation"
C1[lexigram-contracts]
end
subgraph "The Engine"
C2[lexigram]
end
subgraph "The Extensions"
E1(lexigram-web)
E2(lexigram-sql)
E3(lexigram-ai)
E4(lexigram-events)
end
C1 --> C2
C1 -.-> E1 & E2 & E3 & E4
C2 -.-> E1 & E2 & E3 & E4
style C1 fill:#1a1a24,stroke:#4a4a6a,stroke-width:2px,color:#fff
style C2 fill:#2d1b36,stroke:#6a4a8a,stroke-width:2px,color:#fff
style E1 fill:#1b362d,stroke:#4a8a6a,stroke-width:1px,color:#fff
style E2 fill:#1b2d36,stroke:#4a6a8a,stroke-width:1px,color:#fff
style E3 fill:#362d1b,stroke:#8a6a4a,stroke-width:1px,color:#fff
style E4 fill:#361b1b,stroke:#8a4a4a,stroke-width:1px,color:#fff
the rule: extensions never depend on each other — they talk through contracts.