Three foundational decisions
Modular monolith first
One FastAPI application with strict internal module boundaries, not
microservices from day one. Agent execution runs as separate Celery
processes (mandatory for independent scaling) — everything else lives
inside one deployable app until a measured bottleneck justifies
extraction.
The event bus is the coordination primitive
Cross-domain communication flows through typed events on Redis Streams
(
core/events/catalog.py), not synchronous service-to-service calls. A
consumer that needs a result subscribes to an event instead of calling
the producer directly.Tenant isolation is a database primitive
Every tenant-scoped table carries a PostgreSQL Row-Level Security
policy. Application code sets the tenant context per request, but
isolation is enforced by the database even if application code forgets
— see Multi-Tenancy.
System diagram
Layers
MAEL’s dependency direction is strictly one-way:core/ ← apps/ ← agents/
Protocol-based seams (
LLMProvider, RunAgentCallable, AhrefsClient,
PageFetcherClient) let later milestones plug in without refactors — proven
by history: 30+ agents landed on one execution pattern with zero changes to
the runtime layer itself.
Tech stack
Where to go next
AI Agents
The execution spine every agent runs through.
Memory Layer
Session, long-term, vector, and graph memory.
Workflow Engine
DAG execution, checkpointing, idempotency.
Multi-Tenancy
RLS, the sentinel tenant, and the four database roles.