This is the tutorial and example workspace for PyAutoFit. These are the canonical, agent-agnostic instructions for this repo. PyAutoFit is a general-purpose Python framework for Bayesian model fitting and inference — model composition, priors, non-linear searches, samples, the aggregator, and graphical models. It is not tied to any science domain; the examples here are deliberately domain-agnostic toy problems (fitting 1D profiles such as Gaussians).
scripts/— Runnable Python scripts, organised by PyAutoFit feature:overview/— Concise tour of the core features (overview_1_the_basics.pyfirst).searches/— Every non-linear search:nest.py(dynesty, nautilus),mcmc.py(emcee, zeus),mle.py(drawer, LBFGS),start_point.py.model/— Model composition (priors, collections, custom model objects).features/— Advanced features: graphical models, model comparison, search chaining, search grid search, sensitivity mapping, interpolation, shared analysis state.cookbooks/— Focused API cookbooks (model, result, samples, latent variables, …).plot/— Plotting search results (dynesty, emcee, nautilus, zeus, GetDist).simulators/— Scripts that simulate the example datasets fitted throughout.
notebooks/— Jupyter notebook versions, generated fromscripts/(do not edit directly).config/— PyAutoFit configuration YAML files (config/general.yamlcontrols search update intervals, output, logging, profiling, parallel warnings).dataset/— Example 1D datasets.output/— Non-linear search results (generated at runtime, not committed).
There is no projects/ directory.
Scripts are run from the repository root so relative paths to dataset/, config/, and
output/ resolve correctly:
python scripts/overview/overview_1_the_basics.pyThere is currently no start_here.py in this workspace — scripts/overview/overview_1_the_basics.py
is the canonical entry point and the always-current end-to-end reference. (The runner still honours
the convention: if a folder contains a start_here.py, it executes that first, before other
scripts and subfolders, since some scripts depend on results it produces.)
import autofit as af
import autofit.plot as apltFor the canonical workflow (compose a model → configure a search → define an analysis → fit →
inspect results), read scripts/overview/overview_1_the_basics.py — it is kept current with the API.
On CI, every PR is gated by three workflows on Python 3.12 and 3.13: smoke_tests.yml (the
smoke runner below — the definition of green), navigator_check.yml (PyAutoBuild's reusable
navigator-catalogue check; see Notebooks vs Scripts), and url_check.yml (link checking). The
smoke and navigator jobs check out PyAutoBuild as a sibling and run the PyAuto* libraries from
the same-named branch of each source repo, so a workspace PR is validated against matching
library branches.
Two runners exist; both are run from the repo root.
Full runner — executes every script in scripts/:
bash run_scripts.shIt exports PYAUTO_TEST_MODE=1 (plus skip/fast flags), runs each script, writes a log for every
failure to failed/<relative_path>.log, continues past failures, and prints a final
Results: P passed, F failed, S skipped line. The skip list comes from
../PyAutoBuild/autobuild/config/no_run.yaml under the autofit: key; entries whose comment
mentions a bug/issue/fix are flagged [TODO - should run after a future PR].
Smoke runner — executes only the curated subset:
python .github/scripts/run_smoke.pyIt is driven by smoke_tests.txt (scripts) and smoke_notebooks.txt (notebooks) in the workspace
root, with per-entry environment from config/build/env_vars.yaml. It prints a [PASS] /
[FAIL (exit N)] line per entry, ends with a === Smoke test summary: P/T passed === line, and
exits non-zero if any entry failed.
PYAUTO_TEST_MODE is PyAutoFit's own environment variable: it tells the non-linear search to skip
its actual sampling, turning a run into a fast structural / end-to-end check that the model composes
and the script runs to completion — without paying for inference. A script that fails under it
signals a real problem (broken import, renamed API, etc.).
If numba or matplotlib cannot write to their default cache locations, point them at writable
directories:
NUMBA_CACHE_DIR=/tmp/numba_cache MPLCONFIGDIR=/tmp/matplotlib python scripts/overview/overview_1_the_basics.pyNotebooks in notebooks/ are generated from the .py files in scripts/. Always edit the
.py scripts, never the .ipynb notebooks directly. The # %% markers alternate between code
and markdown cells.
After updating scripts, regenerate the notebooks using the PyAutoBuild tool (run from the workspace root):
pip install ipynb-py-convert
git clone https://github.com/PyAutoLabs/PyAutoBuild.git ../PyAutoBuild
PYTHONPATH=../PyAutoBuild/autobuild python3 ../PyAutoBuild/autobuild/generate.py autofitCommit the regenerated notebooks alongside the script changes. The /generate_and_merge skill
automates build + commit + PR + merge.
When editing the same region across many scripts in one pass (adding a section, renaming a symbol, updating an import block), only rewrite the targeted region. Never produce a whole-file write unless you have read the entire current contents of that file — a whole-file write based on a header skim silently deletes every section below the header. Prefer targeted edits.
PyAutoFit is domain-agnostic, so there is no single science field to reference. Any "context" for its examples is statistical / methodological — Bayesian inference, priors, non-linear search, model comparison — not a scientific subject. Do not graft lensing, galaxy, or other domain concepts onto this workspace.
PyAutoFit sits near the base of the PyAuto stack (all on the PyAutoLabs GitHub org):
- https://github.com/PyAutoLabs/PyAutoConf — configuration handling (the
autoconfdependency). - https://github.com/PyAutoLabs/PyAutoFit — this library: model composition + non-linear search.
- https://github.com/PyAutoLabs/PyAutoBuild — notebook generation + CI.
- https://github.com/PyAutoLabs/PyAutoGalaxy — downstream science library built on PyAutoFit.
- https://github.com/PyAutoLabs/PyAutoLens — downstream science library built on PyAutoFit.
- https://github.com/PyAutoLabs/HowToFit — tutorial lecture series that teaches statistical model-fitting and Bayesian inference with PyAutoFit from first principles; the starting point for beginners new to the framework.
For local development these are typically cloned as siblings of this repo (../PyAutoFit,
../PyAutoConf, ../PyAutoBuild, …).
When assigned an issue titled [API Update]:
- Read the PR diff in the issue body. Identify every renamed, moved, removed, or changed public API (functions, classes, method signatures, parameter names, import paths).
- Search all
.pyfiles inscripts/for usages of the old API. - Update each file to the new API, preserving existing behaviour, docstrings, and comments.
- Run
bash run_scripts.shfrom the repo root to test (usepython .github/scripts/run_smoke.pyfor a fast subset). - Read any
failed/<path>.logfiles and fix the affected scripts. - Repeat 4–5 until the suite is clean.
- If a script cannot be fixed (ambiguous change, missing dependency), leave it unchanged and list it in the PR description under "Could not update" with the reason.
- After all scripts pass, regenerate the notebooks (see "Generating notebooks").
When assigned a general (non-API) issue:
- Read the issue description and any linked plan or AI prompt.
- Identify which scripts need to be created or modified.
- Only edit files in
scripts/. Never editnotebooks/directly. - Preserve all docstrings, comments, and tutorial explanations.
- Test with
bash run_scripts.shafter changes. - Regenerate notebooks after all scripts pass.
When opening your PR, include:
- A summary of what changed and why.
- A list of all scripts you updated or created.
- Confirmation that notebooks were regenerated.
- A "Could not update" section for any scripts that still fail, with the error and your assessment.
Never rewrite history on a repo with a remote (no git init over a tracked tree, no force-push to
main, no rebasing pushed shared branches). To reset a dirty tree the only correct sequence is:
git fetch origin
git reset --hard origin/main
git clean -fd