π€ AI Agent Quick Reference GuideΒΆ
Fast-track guide for AI agents to understand and work with the Neuroglia Python Framework
π― Framework OverviewΒΆ
Neuroglia is a clean architecture Python framework built on FastAPI that enforces separation of concerns, CQRS, dependency injection, and event-driven patterns for maintainable microservices.
ποΈ Core ArchitectureΒΆ
src/
βββ api/ # π Controllers, DTOs, Routes (FastAPI)
βββ application/ # πΌ Commands, Queries, Handlers, Services
βββ domain/ # ποΈ Entities, Value Objects, Business Rules
βββ integration/ # π Repositories, External APIs, Infrastructure
Dependency Rule: API β Application β Domain β Integration
β‘ Quick Start PatternsΒΆ
1. CQRS Command/Query PatternΒΆ
# Commands (Write operations)
@dataclass
class CreateOrderCommand(Command[Order]):
customer_id: str
items: List[OrderItemDto]
class CreateOrderHandler(CommandHandler[CreateOrderCommand, Order]):
async def handle_async(self, command: CreateOrderCommand) -> Order:
# Business logic here
return order
# Queries (Read operations)
@dataclass
class GetOrderQuery(Query[Optional[Order]]):
order_id: str
class GetOrderHandler(QueryHandler[GetOrderQuery, Optional[Order]]):
async def handle_async(self, query: GetOrderQuery) -> Optional[Order]:
return await self.repository.get_by_id_async(query.order_id)
2. API Controllers (FastAPI Integration)ΒΆ
from neuroglia.mvc import ControllerBase
from classy_fastapi.decorators import get, post
class OrdersController(ControllerBase):
@post("/", response_model=OrderDto, status_code=201)
async def create_order(self, dto: CreateOrderDto) -> OrderDto:
command = self.mapper.map(dto, CreateOrderCommand)
order = await self.mediator.execute_async(command)
return self.mapper.map(order, OrderDto)
@get("/{order_id}", response_model=OrderDto)
async def get_order(self, order_id: str) -> OrderDto:
query = GetOrderQuery(order_id=order_id)
order = await self.mediator.execute_async(query)
return self.mapper.map(order, OrderDto)
3. Repository PatternΒΆ
# Abstract repository
class OrderRepository(Repository[Order, str]):
async def get_by_customer_async(self, customer_id: str) -> List[Order]:
pass
# MongoDB implementation
class MongoOrderRepository(MongoRepository[Order, str]):
async def get_by_customer_async(self, customer_id: str) -> List[Order]:
cursor = self.collection.find({"customer_id": customer_id})
return [self._to_entity(doc) async for doc in cursor]
4. Dependency Injection & Application SetupΒΆ
from neuroglia.hosting.web import WebApplicationBuilder
from neuroglia.mediation import Mediator
from neuroglia.mapping import Mapper
def create_app():
builder = WebApplicationBuilder()
# Configure core services
Mediator.configure(builder, ["application.commands", "application.queries"])
Mapper.configure(builder, ["application.mapping", "api.dtos", "domain.entities"])
# Register custom services
builder.services.add_scoped(OrderRepository, MongoOrderRepository)
# Add SubApp with controllers
builder.add_sub_app(
SubAppConfig(
path="/api",
name="api",
controllers=["api.controllers"]
)
)
app = builder.build()
return app
5. Observability with OpenTelemetryΒΆ
from neuroglia.observability import configure_opentelemetry, get_tracer, trace_async
# Configure OpenTelemetry (in main.py)
configure_opentelemetry(
service_name="mario-pizzeria",
service_version="1.0.0",
otlp_endpoint="http://localhost:4317"
)
# Use in handlers
tracer = get_tracer(__name__)
class PlaceOrderHandler(CommandHandler):
@trace_async(name="place_order")
async def handle_async(self, command: PlaceOrderCommand):
with tracer.start_as_current_span("validate_order"):
# Business logic with automatic tracing
pass
6. Role-Based Access Control (RBAC)ΒΆ
from fastapi import Depends
from fastapi.security import HTTPBearer
security = HTTPBearer()
class OrdersController(ControllerBase):
@post("/", response_model=OrderDto)
async def create_order(
self,
dto: CreateOrderDto,
credentials: HTTPAuthorizationCredentials = Depends(security)
) -> OrderDto:
# Extract user info from JWT
user_info = self._decode_jwt(credentials.credentials)
# Pass to handler for RBAC check
command = CreateOrderCommand(
customer_id=dto.customer_id,
items=dto.items,
user_info=user_info # Handler checks roles/permissions
)
result = await self.mediator.execute_async(command)
return self.process(result)
# RBAC in handler (application layer)
class CreateOrderHandler(CommandHandler):
async def handle_async(self, command: CreateOrderCommand):
# Authorization check based on roles
if "customer" not in command.user_info.get("roles", []):
return self.forbidden("Insufficient permissions")
# Business logic
order = Order(command.customer_id, command.items)
await self.repository.save_async(order)
return self.created(order)
π§© Framework Modules ReferenceΒΆ
| Module | Purpose | Key Classes |
|---|---|---|
neuroglia.core |
Base types, utilities | OperationResult, Entity, ValueObject |
neuroglia.dependency_injection |
DI container | ServiceCollection, ServiceProvider, ServiceLifetime |
neuroglia.mediation |
CQRS patterns | Mediator, Command, Query, CommandHandler, QueryHandler |
neuroglia.mvc |
FastAPI controllers | ControllerBase, auto-discovery |
neuroglia.data |
Repository & persistence | Repository, MongoRepository, InMemoryRepository, EventStore |
neuroglia.data.resources |
Resource management | ResourceController, ResourceWatcher, Reconciler |
neuroglia.eventing |
Event handling | DomainEvent, EventHandler, EventBus |
neuroglia.eventing.cloud_events |
CloudEvents integration | CloudEvent, CloudEventPublisher, CloudEventIngestor |
neuroglia.mapping |
Object mapping | Mapper, convention-based mapping |
neuroglia.hosting |
App lifecycle | WebApplicationBuilder, WebApplication, HostedService |
neuroglia.serialization |
JSON/data serialization | JsonSerializer, JsonEncoder, TypeRegistry |
neuroglia.validation |
Business rule validation | BusinessRule, ValidationResult, PropertyValidator, EntityValidator |
neuroglia.reactive |
Reactive programming | Observable, Observer (RxPy integration) |
neuroglia.integration |
External services | HttpServiceClient, CacheRepository, BackgroundTaskScheduler |
neuroglia.utils |
Utility functions | CaseConversion, CamelModel, TypeFinder |
neuroglia.expressions |
Expression evaluation | JavaScriptExpressionTranslator |
neuroglia.observability |
OpenTelemetry integration | Tracing, metrics, logging with OTLP exporters |
π Sample ApplicationsΒΆ
The framework includes complete sample applications that demonstrate real-world usage:
π Mario's Pizzeria (samples/mario-pizzeria/)ΒΆ
- Full CQRS implementation with sophisticated domain models
- MongoDB repositories for orders, customers, pizzas
- Event-driven architecture with domain events
- Complete API with OpenAPI documentation
- OpenTelemetry observability with distributed tracing, metrics, and logging
Key Files:
domain/entities/:Order,Pizza,Customerwith business logicapplication/commands/:PlaceOrderCommand,CreatePizzaCommandapplication/queries/:GetOrderByIdQuery,GetMenuItemsQueryapi/controllers/:OrdersController,MenuController
π¦ OpenBank (samples/openbank/)ΒΆ
- Event sourcing with KurrentDB (EventStoreDB)
- CQRS with separate read/write models
- Complex domain modeling (accounts, transactions, persons)
- Banking business rules and validation
- Read model projections and eventual consistency
- Snapshot strategies for performance
π¨ Simple UI (samples/simple-ui/)ΒΆ
- SubApp pattern for UI/API separation
- Stateless JWT authentication without server-side sessions
- Role-Based Access Control (RBAC) at query/command level
- Bootstrap 5 frontend with Parcel bundler
- Clean separation of concerns between UI and API
ποΈ Desktop Controller (samples/desktop-controller/)ΒΆ
- Background services and scheduled tasks
- System integration patterns
- Resource management examples
π§ͺ Lab Resource Manager (samples/lab-resource-manager/)ΒΆ
- Resource-Oriented Architecture (ROA)
- Watcher/Controller patterns (like Kubernetes operators)
- Reconciliation loops for resource management
π API Gateway (samples/api-gateway/)ΒΆ
- Microservice gateway patterns
- AI/ML integration examples
- Service orchestration and routing
- Background task processing with Redis
π Where to Find InformationΒΆ
π Documentation Structure (docs/)ΒΆ
| Section | Purpose | Key Files |
|---|---|---|
getting-started.md |
Framework introduction | Quick start, core concepts |
features/ |
Feature documentation | One file per major feature |
patterns/ |
Architecture patterns | CQRS, Clean Architecture, Event Sourcing |
samples/ |
Sample walkthroughs | Detailed sample explanations |
references/ |
Technical references | Python best practices, 12-Factor App |
guides/ |
Step-by-step tutorials | Mario's Pizzeria tutorial |
π― Key Documentation FilesΒΆ
- Getting Started - Framework overview and quick start
- Mario's Pizzeria Tutorial - Complete walkthrough
- CQRS & Mediation - Command/Query patterns
- MVC Controllers - FastAPI controller patterns
- Data Access - Repository and persistence
- Dependency Injection - DI container usage
- Observability - OpenTelemetry tracing, metrics, logging
- RBAC & Authorization - Role-based access control patterns
- OpenTelemetry Integration - Infrastructure setup guide
- Python Typing Guide - Type hints & generics
π Additional ResourcesΒΆ
README.md- Project overview and installationpyproject.toml- Dependencies and build configurationsrc/neuroglia/- Complete framework source codetests/- Comprehensive test suite with examples
π‘ Common Patterns & Best PracticesΒΆ
β Do ThisΒΆ
# β
Use constructor injection
class OrderService:
def __init__(self, repository: OrderRepository, event_bus: EventBus):
self.repository = repository
self.event_bus = event_bus
# β
Separate commands and queries
class PlaceOrderCommand(Command[Order]): pass
class GetOrderQuery(Query[Optional[Order]]): pass
# β
Use domain events
class Order(Entity):
def place_order(self):
# Business logic
self.raise_event(OrderPlacedEvent(order_id=self.id))
# β
Type hints everywhere
async def handle_async(self, command: PlaceOrderCommand) -> Order:
return order
β Avoid ThisΒΆ
# β Direct database access in controllers
class OrderController:
def create_order(self):
# Don't access database directly
connection.execute("INSERT INTO...")
# β Mixing concerns
class OrderHandler:
def handle(self, command):
# Don't mix business logic with infrastructure
send_email() # Infrastructure concern
# β Missing type hints
def process_order(order): # What type is order?
return result # What type is result?
π Quick CommandsΒΆ
# Install framework (when available)
pip install neuroglia
# Run sample applications
cd samples/mario-pizzeria && python main.py
cd samples/openbank && python main.py
# Run tests
pytest tests/
# Generate documentation
mkdocs serve
# CLI tool (when available)
pyneuroctl --help
pyneuroctl samples list
pyneuroctl new myapp --template minimal
π― For AI Agents: Key TakeawaysΒΆ
- Architecture: Clean Architecture with strict dependency rules
- Patterns: CQRS, DI, Repository, Domain Events are core
- Code Style: Heavy use of type hints, dataclasses, async/await
- Framework Integration: Built on FastAPI, uses Pydantic extensively
- Sample Code: Always reference
samples/mario-pizzeria/for real examples - Documentation: Comprehensive docs in
docs/with practical examples - Testing: Full test coverage with patterns for all architectural layers
- Observability: OpenTelemetry integration for distributed tracing, metrics, and logging
- Security: RBAC patterns with JWT authentication at application layer
- Event Sourcing: Full support with KurrentDB (EventStoreDB) in OpenBank sample
When writing Neuroglia code:
- Follow the layered architecture strictly
- Use CQRS for all business operations
- Leverage dependency injection throughout
- Include comprehensive type hints
- Reference Mario's Pizzeria sample for patterns
- Maintain separation of concerns between layers
- Implement observability with OpenTelemetry decorators
- Handle authorization in handlers (application layer), not controllers
- Use SubApp pattern for clean UI/API separation
π€ Quick Framework Setup for AI AgentsΒΆ
# Minimal Neuroglia application setup
from neuroglia.hosting.web import WebApplicationBuilder
from neuroglia.mediation import Mediator
from neuroglia.mapping import Mapper
def create_app():
builder = WebApplicationBuilder()
# Configure essential services
Mediator.configure(builder, ["application.commands", "application.queries"])
Mapper.configure(builder, ["application.mapping", "api.dtos"])
# Add SubApp with controllers
builder.add_sub_app(
SubAppConfig(
path="/api",
name="api",
controllers=["api.controllers"]
)
)
# Build application
app = builder.build()
return app
if __name__ == "__main__":
app = create_app()
app.run()
Need more detail? Start with Getting Started then dive into specific feature documentation or explore the Mario's Pizzeria sample.