MAEL ships 30+ specialized agents across seven categories. Every one of them runs through the same envelope — retries, idempotency, cost tracking, and evaluation are solved once, centrally, not reimplemented per agent.

Agent categories

One execution spine (ADR-008)

LifecycleManager.run() is the envelope for every agent run — ADR-006 idempotency layers, run-log state transitions, and lifecycle events happen here regardless of what the agent itself does. Custom agent bodies are dispatched through the manifest’s "entrypoint": "<module>:build_runner", so an agent can own real nested Pydantic schemas and multi-step logic (a tool call before an LLM call, deterministic post-processing) without touching the shared envelope. Every step-executing agent in agents/*/*/ agent.py exposes ENTRYPOINT / build_runner() / execute() — enforced by a test that imports and checks every agent module.
This replaced an earlier split where 30+ agents used a direct-composition pattern separate from the shared lifecycle class. ADR-008 folded both into one spine so quality/cost/evaluation improvements apply everywhere at once, not per-agent.

Evaluation (ADR-009): never a silent auto-pass

Evaluation is opt-in per agent — assigned via the manifest’s "evaluator": "<module>:factory". This is a deliberate design choice: an agent with no evaluator is recorded as not evaluated (NULL score, seo_agent_evaluations_total{outcome="not_evaluated"}), never silently scored as a pass. The dashboard and alerting both distinguish not_evaluated from passed — visibility into which agents are gated and which aren’t is the point. For content specifically, full-content-pipeline.yaml adds a dedicated content-evaluation step (ADR-011) between review and human approval, scoring nine dimensions — SEO, E-E-A-T, medical compliance, readability, hallucination risk, AI-detection risk, internal linking, schema validity, brand voice — with medical compliance and hallucination risk as hard, fail-closed dimensions: a YMYL (medical) article with no fact-check output fails the gate outright, regardless of composite score. A FAIL routes the article to review_required; a PASS still requires human approval — the gate never auto-publishes.

Multi-LLM routing (ADR-007) and resilience (ADR-010)

Providers — Anthropic, OpenAI, Google, Ollama, vLLM — load lazily through a provider registry (core/agent_runtime/providers/registry.py); an agent’s model_config in its manifest picks the model, never a hardcoded provider in code. ModelRouter retries with exponential backoff, then fails over to a configured fallback model. A process-wide circuit breaker per provider trips after consecutive failures and fast-fails to the fallback chain — no wasted timeout/retry budget on a provider that’s actually down — and closes again after a cooldown probe succeeds.

Idempotency (ADR-006)

Every agent/step execution is protected by three layers: a Redis lock (prevents concurrent execution of the same logical run), a unique constraint on the run-log insert (prevents duplicate rows even under a lock race), and consumer-level dedup on the event that triggered the run. A Celery task redelivered after a visibility timeout, or a duplicate event delivery, cannot cause double execution or double side effects.

Cost tracking

Every LLM call is recorded to a partitioned billing.usage_events table with per-call cost attribution, rolled up per agent run and per tenant. Budget Guard enforces tenant monthly_budget_usd pre-dispatch — a run that would exceed budget never starts. Spend alerts fire at 50/hour(warning)and50/hour (warning) and 200/hour (critical), with a documented kill-switch procedure.

Memory Layer

Workflow Engine