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.