This guide walks you through a complete end-to-end example using HexCore’s core building blocks: aDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Indroic/HexCore/llms.txt
Use this file to discover all available pages before exploring further.
BaseEntity domain entity, a Command, an AbstractCommandHandler, a HandlerRegistry, and an InMemoryCommandBus. By the end you will have a runnable Python script that models a Product aggregate and handles a CreateProduct command entirely in memory — perfect for unit-testing your domain logic without any database.
Install the package from PyPI. Core dependencies (Pydantic v2, Typer, croniter) are included automatically.
Python 3.12 or later is required. For database, API, or message-queue support see the Installation guide for the available extras.
Every aggregate root in HexCore extends
BaseEntity. It ships with four built-in fields (id, created_at, updated_at, is_active) so you only need to add the fields that belong to your domain model.from uuid import UUID
from hexcore.domain.base import BaseEntity
class Product(BaseEntity):
"""A simple product aggregate root."""
name: str
price: float
stock: int = 0
BaseEntity is backed by Pydantic v2 with validate_assignment=True, so field values are validated every time they change. The id field defaults to a fresh uuid4, and both timestamp fields default to datetime.now(UTC).A
Command represents an intent to change state. It is immutable (frozen=True) and carries a command_id and timestamp automatically.from hexcore.domain.cqrs.commands import Command
class CreateProductCommand(Command):
name: str
price: float
initial_stock: int = 0
Commands are Pydantic models — you get automatic validation, serialization, and type-safety for free. Pass them directly to your API request schemas if you like.
AbstractCommandHandler is a generic ABC with a single abstract method: handle(command). The type parameters declare the command type and the return type; use None for fire-and-forget commands.from hexcore.domain.cqrs.handlers import AbstractCommandHandler
from hexcore.domain.cqrs.commands import Command
class CreateProductHandler(AbstractCommandHandler[CreateProductCommand, Product]):
"""Handles the CreateProductCommand and returns the new Product entity."""
async def handle(self, command: CreateProductCommand) -> Product:
product = Product(
name=command.name,
price=command.price,
stock=command.initial_stock,
)
# In a real application you would persist via a repository here:
# product = await self.repository.save(product)
return product
HandlerRegistry maps each command type to its handler. Pass the registry to InMemoryCommandBus and you have a fully working command bus — no configuration files required.from hexcore.application.cqrs.registry import HandlerRegistry
from hexcore.application.cqrs.in_memory_buses import InMemoryCommandBus
registry = HandlerRegistry()
registry.register_command_handler(CreateProductCommand, CreateProductHandler())
bus = InMemoryCommandBus(registry=registry)
Complete working example
Below is the full script combining all of the steps above. Copy it into a file nameddemo.py, run pip install hexcore, then execute python demo.py.
Next steps
Installation
Add optional extras for FastAPI, SQLAlchemy, Redis, MongoDB, or task queues.
CQRS Pattern
Learn about queries, event buses, middlewares, and smart background routing.
Domain-Driven Design
Explore entities, value objects, domain events, repositories, and services.
Hexagonal Architecture
Understand ports, adapters, and how HexCore organises the three layers.