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

BlockPurpose
model.class, model.kwargsPublic class and constructor settings
dataX_path and optional y_path
runInference method, progress display, output directory and run name
effects, extra_varsCustom effect specifications and auxiliary data
original_scale_varsDeterministics to register before fitting
calibrationOrdered supported method calls
holidaysCalendar mode, file, countries and prefix
diagnosticsComplete gate profile and threshold overrides
validationFresh aggregate blocked-tail fit
prior_sensitivityScenario configurations and optional additional fits
ai_advisorLocal 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).

ControlEffective default or meaning
positional target, --config, --demoMutually exclusive; default demo timeseries; directories contain config.yml
--list-demosList bundled names and exit
--version; -h, --helpPrint package version or parser help and exit
--holidaysOverride calendar file; an explicit relative override starts at the process directory
--dry-runSource-config and graph validation only
--quickchains=2, cores=2, tune=300, draws=300; prior samples 10, curve draws 25, curve points 50; disables holdout and prior sensitivity
--draws, --tune, --chains, --coresPositive integers overriding YAML; CLI --tune 0 is rejected although validation YAML permits zero
--random-seedInteger fit-seed override; no CLI default; not a seed for every subsequent operation
--methodOverride mcmc, map, demz, advi or fullrank_advi; holdout requires mcmc
--prior-samples20 unless overridden or quick mode is selected
--curve-samples100 posterior curve draws unless overridden or quick mode is selected
--curve-points100 points unless overridden or quick mode is selected
--no-validationDisable configured fresh holdout fit
--no-prior-sensitivityDisable both scenario preparation and alternative fits
--no-ai-advisorDisable both local/provider advisor stages
--results-dirOverride run.output_dir; relative paths start beside runme.py
--run-nameOverride YAML name or filename stem; quick mode appends _quick unless this flag is explicit
--quiet, --verboseMutually exclusive terminal verbosity settings
--scenario-recipe, --model, --scenario-outputAll 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).

BlockFields and defaultsValidation / ownership
model, each effects entryclass required, args: [], kwargs: {}Recursive trusted Python construction; class_ is the accepted field-name alias
dataX_path: null, y_path: nullBuilder can use supplied objects instead; target must be available from X or y
runmethod: mcmc, progressbar: true, output_dir: results, run_name: nullNon-empty output/name; name otherwise defaults to YAML stem
holidaysenabled: true, mode: prophet_component, path: null, countries: null, prefix: holidayModes event, pooled_control, prophet_component; non-empty prefix/countries; see holiday guide
validationenabled: 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.samplerdraws, tune, chains, cores, random_seed, target_accept, compute_convergence_checks: all nullPositive counts except tune >= 0; 0 < target_accept < 1; non-null values override model sampler
effectsnull or ordered list of build specificationsAttach before graph construction
extra_varsnull or list of auxiliary column namesRetain columns as canonical xarray variables; not automatically controls
original_scale_varsnull or list of graph variable namesRegister before calibration and fitting
calibrationnull or ordered method calls; each call has parameters or nullCallable model methods; lift dist override is rejected; see calibration guide
idata_pathnull or stringDirect-builder attachment, enabled by load_idata=True; use false for a fresh fit
diagnosticsnull or policy configurationComplete profile plus optional overrides; see diagnostic guide
prior_sensitivity, ai_advisornull or mappingsRunner 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 fieldDefault / constraint
enabled, reference, scenario_policytrue, reference, manual; policy also accepts conservative_mmm
allow_model_structure_overrides, fit_scenariosfalse, false
robustness_tolerance0.2, strictly positive; relative comparison policy, not probability of robustness
scenariosEmpty mapping; lowercase non-reserved names
Each scenariodescription: 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 fieldDefault / constraint
enabled, providerfalse, openrouter; alternative openai
mode, privacy, approvalFixed autopilot, anonymized_relative, file_based
write_outputs, llm_enabled, diagnostics_review_enabledtrue for all three; explicitly disable the LLM for local-only review
modelnull selects the provider-specific code default; explicit value must be non-empty
timeout_seconds60, 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.