Architecture & Flow Diagrams
One repository, several deliberately separable layers. At v1.0.0 the framework is a uv workspace with a lean modeling core and optional application layers on top — install exactly as much of the platform as you need.
The split is simple to state: pip install mmm-framework gives you the
business logic only — the Bayesian modeling engine on the PyMC 6 stack,
with reporting, validation, planning, and estimands, and nothing that phones an LLM or
serves HTTP. The mmm-framework[agents] extra adds the LangGraph
oracle (langgraph / langchain, plus httpx, pypdf, and
python-docx for knowledge-base ingestion). The web application is its own
package: mmm-framework-server (repo directory
server/, Python package mmm_framework_server) is the FastAPI app,
run with uvicorn mmm_framework_server.main:app. The frontend/
directory holds the React UI that talks to it over HTTP and SSE.
One rename matters if you knew the pre-1.0 layout: the former
mmm_framework.api service modules — the sessions store, run history,
pacing, scorecard, triangulation, backfill, backup, and friends — are now
mmm_framework.platform. They are dependency-light and shared
by both the agents layer and the server, so the core package can carry them without
dragging in a web stack. A lean-import gate test
(tests/test_lean_imports.py) pins the invariant: importing the core must not
pull the agent or server dependencies.
Install what you need
# Modeling core only — PyMC 6 stack, no LLM, no web server
pip install mmm-framework
# Core + the LangGraph oracle agent (langgraph/langchain, httpx, pypdf, python-docx)
pip install "mmm-framework[agents]"
# The FastAPI application (depends on mmm-framework[agents])
pip install mmm-framework-server
uvicorn mmm_framework_server.main:app --host 0.0.0.0 --port 8000
# Optional data-integration extras for the core
pip install "mmm-framework[gcp]" # GCS + BigQuery readers
pip install "mmm-framework[s3]" # S3 object store
💡 Who this page is for
Technical evaluators and developers deciding what to deploy where. If you want the guided product tour instead, start with the Platform Overview; if you want to fit a model in ten minutes, start with Getting Started.
1 · Package & dependency architecture
Dependencies point in exactly one direction: the server depends on the core with the
agents extra, the agents extra depends on the core, and the core depends on nothing
above it. The React frontend is not a Python dependency at all — it speaks HTTP and SSE
to the server. The session kernel image is a deploy artifact built from the lean
core (plus ipykernel, python-pptx, and matplotlib
for in-kernel deck and chart rendering) and deliberately carries no LLM or web stack:
user code executed in a session never has the credentials or the libraries to call out.
React + Vite UI"] SRV["mmm-framework-server
FastAPI app · repo server/ · package mmm_framework_server"] AGENTS["mmm-framework with the agents extra
LangGraph oracle · langgraph, langchain, httpx, pypdf, python-docx"] CORE["mmm-framework — the core
model · transforms · config + builders · reporting · validation
planning · estimands · diagnostics · eda · synth · platform · auth core"] KERNEL["session kernel image
lean core + ipykernel + python-pptx + matplotlib
no LLM or web stack"] GCP["gcp extra
GCS + BigQuery"] S3["s3 extra
S3 object store"] FE -->|"HTTP + SSE"| SRV SRV -->|"depends on"| AGENTS AGENTS -->|"depends on"| CORE KERNEL -->|"built from"| CORE GCP -.->|"optional extra of"| CORE S3 -.->|"optional extra of"| CORE style FE fill:#e6f0f7,stroke:#4a6d8a style SRV fill:#f7f0e6,stroke:#8a6d4a style AGENTS fill:#f0e6f7,stroke:#6d4a8a style CORE fill:#f0f7e6,stroke:#6d8a4a style KERNEL fill:#e6f7f0,stroke:#4a8a6d
- The core is embeddable.
pip install mmm-frameworkin a notebook or a batch pipeline gives you the full modeling engine with no agent or web baggage — the lean-import gate test keeps it that way. - The agents layer is an extra, not a fork. The lazy
agents/__init__means the langchain-free agent modules import without the extra; only the LLM-facing modules need it. - The kernel image is intentionally blind. Session code runs against the lean core in a sandbox with a scrubbed environment — no API keys, no web client libraries.
2 · Model-building data flow
The modeling pipeline is a straight line from data to a fitted posterior, then a fan-out
into everything you do with one. Data arrives as an MFF (Master Flat File) CSV, a wide
CSV, or a bundled load_example() dataset; MFFLoader validates it
(schema, cadence, coverage) and produces a PanelDataset; BayesianMMM
builds the PyMC graph — adstock, then saturation, then trend, seasonality, and controls,
then the likelihood — and fits it with full NUTS (PyMC or numpyro), an approximate method
for fast iteration (MAP, ADVI, pathfinder, Laplace), or tempered SMC, which is exact.
Everything downstream consumes the same MMMResults object.
long format"] WIDE["wide CSV"] EX["load_example()"] end LOAD["MFFLoader
validation · cadence checks"] PANEL["PanelDataset"] MODEL["BayesianMMM
adstock → saturation → trend, seasonality, controls → likelihood
fit: NUTS / numpyro · approximate MAP, ADVI, pathfinder, Laplace · SMC exact"] RES["MMMResults
posterior · diagnostics · estimands"] subgraph OUT["Fan-out"] REP["MMMReportGenerator
Augur HTML readout"] IREP["InteractiveReportGenerator
recompute-in-browser report"] SER["MMMSerializer
persisted model directory"] ANA["analysis + estimands
ROI · marginal ROAS · counterfactuals"] VAL["validation
backtests · SBC · refutation"] end MFF --> LOAD WIDE --> LOAD EX --> LOAD LOAD --> PANEL PANEL --> MODEL MODEL --> RES RES --> REP RES --> IREP RES --> SER RES --> ANA RES --> VAL style IN fill:#e6f0f7,stroke:#4a6d8a style OUT fill:#f0f7e6,stroke:#6d8a4a style MODEL fill:#f7f0e6,stroke:#8a6d4a
- Validation happens at the door.
MFFLoaderrejects malformed panels (cadence gaps, duplicate cells, missing dims) before a model ever sees them. - Approximate fits are first-class but labelled. A MAP or ADVI
MMMResultsis a drop-in for iteration, and every downstream surface — reports, serialization, run history — carries the approximate flag so uncalibrated uncertainty is never mistaken for a full posterior. - The fan-out is symmetric. Reports, the interactive report, the serializer, analysis, and the validation suite all read the same posterior; there is no second code path for "the numbers in the report."
3 · Application request flow
When the full application is deployed, a chat turn traces a single round trip. The React
UI (dev port 5173) opens an SSE stream against the FastAPI server's /chat
endpoint (port 8000); the server resumes the LangGraph agent from its checkpoint; the
agent — held to one workflow step per user turn by the workflow-step guard — calls tools;
heavy work (including model fits) runs inside the per-session kernel, which can be
in-process, a subprocess, or a sandboxed container; durable state lands in the SQLite
sessions store under mmm_framework.platform.sessions. Results stream back as
typed SSE events and render into the workspace tabs.
one pipeline milestone per turn Agent->>Tools: Tool call (EDA, build, fit, report, ...) Tools->>Kernel: execute_python — fits run in-kernel Kernel-->>Tools: stdout, plots, tables Tools->>Store: Persist artifacts, experiments, run metrics Store-->>API: Session state and artifact refs API-->>UI: SSE events — messages, plots, tables, artifacts UI-->>User: Rendered in the workspace tabs
- Fits run in the kernel, not in a queue. There is no Redis worker or external job service to operate — the kernel is the compute boundary, and it scales from in-process (dev) to a sandboxed container (hosted) without changing the flow.
- The agent is throttled by design. The workflow-step guard stops an orchestrator from auto-running the whole nine-step pipeline off one high-level ask; the user advances the workflow one milestone at a time.
- Everything the UI shows is replayable. Plots, tables, and report artifacts are content-addressed and session-scoped in the store, so a reloaded session reconstructs its workspace without re-running anything.
4 · The measurement loop
The product story is not a one-off model fit — it is an adaptive measurement cycle. A
fitted, calibration-aware MMM (T₀) tells you where the posterior is weakest; expected
information gain and expected value of information rank which experiment to run next
(T₁); experiments are designed and pre-registered with a full lifecycle —
draft → planned → running → completed → calibrated (T₂); completed readouts enter the
next refit as in-graph experiment likelihoods, not post-hoc adjustments (T₃); the
calibrated model drives budget allocation (T₄); and information decay triggers re-tests
as the market drifts (T₅), feeding the next round of priorities. The experiment registry
and its lifecycle live in mmm_framework.platform.sessions.
Bayesian MMM with calibration"] T1["T₁ · Prioritize
EIG / EVOI per channel"] T2["T₂ · Design + pre-register
geo lift · DiD · flighting
draft → planned → running → completed → calibrated"] T3["T₃ · Calibrated refit
experiment likelihoods in-graph"] T4["T₄ · Allocate
budget optimizer"] T5["T₅ · Re-evaluate
information decay triggers re-tests"] T0 --> T1 T1 --> T2 T2 --> T3 T3 --> T4 T4 --> T5 T5 -->|"new priorities"| T1 style T0 fill:#f0f7e6,stroke:#6d8a4a style T3 fill:#f0f7e6,stroke:#6d8a4a style T1 fill:#e6f0f7,stroke:#4a6d8a style T5 fill:#e6f0f7,stroke:#4a6d8a style T2 fill:#f7f0e6,stroke:#8a6d4a style T4 fill:#f7f0e6,stroke:#8a6d4a
- Experiments are pre-registered, not retrofitted. The lifecycle registry enforces legal transitions and audits every readout, so a calibrated number has a paper trail from draft onward.
- Calibration is in the likelihood. A completed experiment constrains the refit as an in-graph likelihood term on the matching estimand — the posterior moves for the right structural reason.
- The loop is the deliverable. EIG/EVOI priorities, design economics, and decay-triggered re-tests turn a static report into a standing measurement program.
Where things live
A quick map from subsystem to import path. Everything in the first column below the double rule ships in the core package; the last two rows are the agents extra and the separate server package.
| Subsystem | Import path |
|---|---|
| Core modeling (engine, transforms, configuration) | mmm_framework.model · .transforms · .builders · .config |
| Data loading and panels | mmm_framework.data_loader · .dataset · .datasets |
| Inference results | mmm_framework.model.results |
| Estimands (named, serializable causal quantities) | mmm_framework.estimands |
| Reporting (Augur readout, interactive report, decks) | mmm_framework.reporting |
| Validation and diagnostics (backtests, SBC, coverage, refutation) | mmm_framework.validation · .diagnostics |
| Experiment planning (EIG/EVOI, design, economics, optimizer) | mmm_framework.planning |
| Platform services (sessions store, run history, pacing, scorecard, triangulation, backfill, backup) | mmm_framework.platform |
Agent — LangGraph oracle (requires the agents extra) | mmm_framework.agents |
| Server — FastAPI application (separate package) | mmm_framework_server.main |
Where to go next
The shapes on this page are frozen by contract: the request/response schemas and artifact formats the diagrams gesture at are specified in API Contracts, and every server endpoint is documented in the REST API reference. For the guided product walkthrough see the Platform Overview, and to fit your first model, Getting Started.
See it in motion
The diagrams are the map — the contracts and the quickstart are the territory.