Run from YAML
Use runme.py when you want configuration-driven fitting with retained outputs.
YAML class paths can import Python objects, so run only trusted configurations.
A dry run validates inputs and builds the main graph without fitting or writing
run artefacts; it does not prove that later stages will succeed.
uv run --no-sync python runme.py --list-demos
uv run --no-sync python runme.py geo_fe --dry-run --no-ai-advisor
uv run --no-sync python runme.py --help
The default target is timeseries. Demos using prophet_component holidays
need uv sync --locked --extra holidays before preparing a new profile.
A quick execution check still fits a model:
uv run --no-sync python runme.py timeseries --quick --no-ai-advisor
--quick selects two chains, 300 tuning iterations and 300 retained draws,
reduces curve sampling, and disables holdout and prior-sensitivity stages.
Explicit sampler flags override quick defaults. These settings test the
workflow; inspect diagnostics before using any posterior result.
Minimal configuration
Save this as sandbox/model.yml and provide sandbox/data.csv with regular
dates and columns date, revenue, tv and social. This example uses no
optional holidays or live advisor.
model:
class: ammm.mmm.MMM
kwargs:
date_column: date
target_column: revenue
channel_columns: [tv, social]
adstock:
class: ammm.mmm.GeometricAdstock
kwargs: {l_max: 4}
saturation:
class: ammm.mmm.LogisticSaturation
sampler_config:
nuts_sampler: pymc
chains: 4
cores: 1
tune: 1000
draws: 1000
random_seed: 42
target_accept: 0.95
data:
X_path: data.csv
run:
method: mcmc
output_dir: results
run_name: example
original_scale_vars: [y, channel_contribution]
ai_advisor:
enabled: false
uv run --no-sync python runme.py sandbox/model.yml --dry-run
uv run --no-sync python runme.py sandbox/model.yml
target_column names the input outcome; predictive graph variables still use
y. The builder can read the target from X or a separate data.y_path.
Through runme.py, relative data and configured holiday paths resolve from the
YAML directory. The direct Python builder resolves data paths from the process
working directory; pass preloaded X and y or absolute data paths there.
Configured holiday paths remain YAML-relative in both routes
(src/ammm/pipeline/runner.py:356, src/ammm/mmm/builders/yaml.py:137).
Relative runner output paths resolve beside runme.py, not beside the YAML.
Configuration blocks
| Block | Purpose |
|---|---|
model.class, model.kwargs | Public class and constructor settings |
data | X_path and optional y_path |
run | Inference method, progress display, output directory and run name |
effects, extra_vars | Custom effect specifications and auxiliary data |
original_scale_vars | Deterministics to register before fitting |
calibration | Ordered supported method calls |
holidays | Calendar mode, file, countries and prefix |
diagnostics | Complete gate profile and threshold overrides |
validation | Fresh aggregate blocked-tail fit |
prior_sensitivity | Scenario configurations and optional additional fits |
ai_advisor | Local rules and optional provider review |
The builder also accepts idata_path; fresh-fit and holdout workflows must not
silently reuse an existing posterior. In Python, use
build_mmm_from_yaml(path, X=X, y=y, load_idata=False) with prepared inputs
when building for a new fit. A configured idata_path is process-relative in
the direct builder, and a nonexistent file is silently left unattached; use
MMM.load for validated model restoration (src/ammm/mmm/builders/yaml.py:237).
Unknown top-level and typed-block keys are rejected. Constructor and nested
object dictionaries are resolved by their corresponding interfaces.
CLI controls
Inputs are a positional demo/file/directory, --config, or --demo.
--holidays overrides the calendar file. Sampler controls include --draws,
--tune, --chains, --cores, --random-seed and --method.
Use --prior-samples, --curve-samples and --curve-points for pipeline
sampling sizes. Positive-integer CLI controls reject zero, including --tune.
--no-validation, --no-prior-sensitivity and --no-ai-advisor disable their
stages. --results-dir and --run-name set output placement.
--quiet reduces terminal detail; --verbose adds library output and tracebacks.
Use --help for the full parser rather than assuming AMMM3 flags remain valid.
Inspect the manifest and output files, diagnostic status and any holdout evidence. CLI completion and model qualification are separate results.
Effective defaults and execution boundaries
The retained runner requires link="identity": response preparation rejects an
ordinary log-link model before fitting, including during dry-run validation.
Experimental log-link use belongs to the Python interface
(src/ammm/pipeline/stages/core.py:130). The FE runner uses within-unit contrast
plots for prior checks and outcome-level plots after fitting; see the
FE contract. Enabled holdout validation rejects
non-empty calibration before execution; see the holdout contract.
For a real invocation, explicit CLI values override quick-mode values, which
override the corresponding YAML sampler settings. Unspecified sampler values
remain with the model/backend defaults; the CLI does not invent a universal
chain count or seed. Sampler overrides also update configured validation sampler
settings (runme.py:313, src/ammm/pipeline/runner.py:340).
A dry run branches before those overrides: it validates the source YAML and
builds the main graph without applying quick, sampler, stage-disable or output
controls. An explicit holiday-file override is forwarded. Consequently,
--dry-run --quick does not validate the configuration used by --quick
(runme.py:163).
| Control | Effective default or meaning |
|---|---|
positional target, --config, --demo | Mutually exclusive; default demo timeseries; directories contain config.yml |
--list-demos | List bundled names and exit |
--version; -h, --help | Print package version or parser help and exit |
--holidays | Override calendar file; an explicit relative override starts at the process directory |
--dry-run | Source-config and graph validation only |
--quick | chains=2, cores=2, tune=300, draws=300; prior samples 10, curve draws 25, curve points 50; disables holdout and prior sensitivity |
--draws, --tune, --chains, --cores | Positive integers overriding YAML; CLI --tune 0 is rejected although validation YAML permits zero |
--random-seed | Integer fit-seed override; no CLI default; not a seed for every subsequent operation |
--method | Override mcmc, map, demz, advi or fullrank_advi; holdout requires mcmc |
--prior-samples | 20 unless overridden or quick mode is selected |
--curve-samples | 100 posterior curve draws unless overridden or quick mode is selected |
--curve-points | 100 points unless overridden or quick mode is selected |
--no-validation | Disable configured fresh holdout fit |
--no-prior-sensitivity | Disable both scenario preparation and alternative fits |
--no-ai-advisor | Disable both local/provider advisor stages |
--results-dir | Override run.output_dir; relative paths start beside runme.py |
--run-name | Override YAML name or filename stem; quick mode appends _quick unless this flag is explicit |
--quiet, --verbose | Mutually exclusive terminal verbosity settings |
--scenario-recipe, --model, --scenario-output | All required together; incompatible with fit-runner controls; destination must be new |
These controls are defined in runme.py:31, runme.py:193 and runme.py:340.
Exit 0 means dispatch/execution succeeded, including a completed run with failed
diagnostic gates; exit 1 reports a runtime exception, exit 2 an argparse error,
and exit 130 an interrupted invocation (runme.py:387). Read the manifest and
diagnostic policy before accepting results.
Typed YAML field reference
Only model is required by MMMYamlConfig; the runner also requires
run. Optional blocks default to absent and therefore do not run merely because
a nested class has enabled: true as its own default. Unknown typed fields are
rejected (src/ammm/mmm/builders/schema.py:233, runme.py:88).
| Block | Fields and defaults | Validation / ownership |
|---|---|---|
model, each effects entry | class required, args: [], kwargs: {} | Recursive trusted Python construction; class_ is the accepted field-name alias |
data | X_path: null, y_path: null | Builder can use supplied objects instead; target must be available from X or y |
run | method: mcmc, progressbar: true, output_dir: results, run_name: null | Non-empty output/name; name otherwise defaults to YAML stem |
holidays | enabled: true, mode: prophet_component, path: null, countries: null, prefix: holiday | Modes event, pooled_control, prophet_component; non-empty prefix/countries; see holiday guide |
validation | enabled: true, holdout_observations: 8, include_last_observations: true, coverage_levels: [0.5, 0.8, 0.94], posterior_predictive_random_seed: 43, sampler: {} | Positive holdout; carry-in fixed true; coverage tuple fixed exactly |
validation.sampler | draws, tune, chains, cores, random_seed, target_accept, compute_convergence_checks: all null | Positive counts except tune >= 0; 0 < target_accept < 1; non-null values override model sampler |
effects | null or ordered list of build specifications | Attach before graph construction |
extra_vars | null or list of auxiliary column names | Retain columns as canonical xarray variables; not automatically controls |
original_scale_vars | null or list of graph variable names | Register before calibration and fitting |
calibration | null or ordered method calls; each call has parameters or null | Callable model methods; lift dist override is rejected; see calibration guide |
idata_path | null or string | Direct-builder attachment, enabled by load_idata=True; use false for a fresh fit |
diagnostics | null or policy configuration | Complete profile plus optional overrides; see diagnostic guide |
prior_sensitivity, ai_advisor | null or mappings | Runner validates these through their own typed schemas below |
Field constraints are implemented at src/ammm/mmm/builders/schema.py:89.
Nested dictionaries with class build objects recursively; ordinary mappings,
lists and scalar values are resolved by the factory. For example,
{class: pymc_extras.prior.Prior, args: [Normal], kwargs: {mu: 0, sigma: 1}}
constructs a prior rather than naming a new root YAML field
(src/ammm/mmm/builders/factories.py:80).
| Prior-sensitivity field | Default / constraint |
|---|---|
enabled, reference, scenario_policy | true, reference, manual; policy also accepts conservative_mmm |
allow_model_structure_overrides, fit_scenarios | false, false |
robustness_tolerance | 0.2, strictly positive; relative comparison policy, not probability of robustness |
scenarios | Empty mapping; lowercase non-reserved names |
| Each scenario | description: null, reason: null, overrides: {} with dotted paths; reference cannot override |
The schema is src/ammm/prior_sensitivity/config.py:31; the
prior-sensitivity example
shows valid paths and retained evidence.
| Advisor field | Default / constraint |
|---|---|
enabled, provider | false, openrouter; alternative openai |
mode, privacy, approval | Fixed autopilot, anonymized_relative, file_based |
write_outputs, llm_enabled, diagnostics_review_enabled | true for all three; explicitly disable the LLM for local-only review |
model | null selects the provider-specific code default; explicit value must be non-empty |
timeout_seconds | 60, at least 1 |
These are code defaults at the reviewed commit, not a statement of current
provider availability or pricing (src/ammm/pipeline/config.py:42). See
advisor operations
for the privacy, usage and approval boundaries.
Implementation reference at 7cb7f20: runme.py:193, src/ammm/mmm/builders/schema.py:233, src/ammm/mmm/builders/yaml.py:73.