Metadata-Version: 2.4
Name: buildml
Version: 2.4.0a3
Summary: BuildML: a flexible, depth-first toolkit for building ML workflows.
Author-email: Leonard Onyiriuba <leonard.c.onyiriuba@gmail.com>
License: Apache-2.0
Project-URL: Homepage, https://github.com/TechLeo-Libraries/BuildML
Project-URL: Documentation, https://buildml.readthedocs.io/
Keywords: machine learning,data science,data preprocessing,supervised learning,ML toolkit
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: <3.14,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: numpy>=1.23
Requires-Dist: pandas>=2.0
Requires-Dist: pyarrow>=14.0
Requires-Dist: scikit-learn>=1.3
Provides-Extra: polars
Requires-Dist: polars>=0.20; extra == "polars"
Provides-Extra: duckdb
Requires-Dist: duckdb>=0.10; extra == "duckdb"
Provides-Extra: engines
Requires-Dist: buildml[duckdb,polars]; extra == "engines"
Provides-Extra: optuna
Requires-Dist: optuna>=3.4; extra == "optuna"
Provides-Extra: automl
Requires-Dist: buildml[optuna]; extra == "automl"
Provides-Extra: automl-industry
Requires-Dist: buildml[automl]; extra == "automl-industry"
Requires-Dist: flaml>=2.1; extra == "automl-industry"
Requires-Dist: autogluon.tabular>=1.1; extra == "automl-industry"
Requires-Dist: lightgbm>=4.0; extra == "automl-industry"
Requires-Dist: xgboost>=2.0; extra == "automl-industry"
Requires-Dist: catboost>=1.2; extra == "automl-industry"
Provides-Extra: torch
Requires-Dist: torch>=2.2; extra == "torch"
Requires-Dist: pillow>=9.0; extra == "torch"
Requires-Dist: soundfile>=0.12; extra == "torch"
Provides-Extra: ssl
Requires-Dist: buildml[torch]; extra == "ssl"
Requires-Dist: sentence-transformers>=2.2; extra == "ssl"
Requires-Dist: transformers>=4.36; extra == "ssl"
Provides-Extra: dl
Requires-Dist: buildml[torch]; extra == "dl"
Provides-Extra: audio
Requires-Dist: buildml[torch]; extra == "audio"
Provides-Extra: speech
Requires-Dist: buildml[torch]; extra == "speech"
Requires-Dist: transformers>=4.36; extra == "speech"
Provides-Extra: vision
Requires-Dist: buildml[torch]; extra == "vision"
Requires-Dist: torchvision>=0.17; extra == "vision"
Provides-Extra: pretrained
Requires-Dist: buildml[speech,vision]; extra == "pretrained"
Provides-Extra: onnx
Requires-Dist: onnx>=1.15; extra == "onnx"
Provides-Extra: rag
Requires-Dist: sentence-transformers>=2.2; extra == "rag"
Requires-Dist: transformers>=4.36; extra == "rag"
Provides-Extra: rag-advanced
Requires-Dist: buildml[rag]; extra == "rag-advanced"
Requires-Dist: langchain-community>=0.2; extra == "rag-advanced"
Requires-Dist: langchain-core>=0.2; extra == "rag-advanced"
Provides-Extra: graph
Requires-Dist: networkx>=3.0; extra == "graph"
Provides-Extra: graph-pyg
Requires-Dist: buildml[torch]; extra == "graph-pyg"
Requires-Dist: torch-geometric>=2.5; extra == "graph-pyg"
Provides-Extra: rl
Requires-Dist: gymnasium>=0.29; extra == "rl"
Provides-Extra: rl-industry
Requires-Dist: buildml[rl]; extra == "rl-industry"
Requires-Dist: stable-baselines3>=2.3; extra == "rl-industry"
Requires-Dist: imitation>=1.0; extra == "rl-industry"
Requires-Dist: torch>=2.2; extra == "rl-industry"
Provides-Extra: tda
Requires-Dist: ripser>=0.6; extra == "tda"
Requires-Dist: persim>=0.3; extra == "tda"
Provides-Extra: tda-industry
Requires-Dist: buildml[tda]; extra == "tda-industry"
Requires-Dist: giotto-tda>=0.6; python_version < "3.13" and extra == "tda-industry"
Provides-Extra: ai
Requires-Dist: openai>=1.0; extra == "ai"
Provides-Extra: llm
Requires-Dist: buildml[ai]; extra == "llm"
Provides-Extra: imbalanced
Requires-Dist: imbalanced-learn>=0.11; extra == "imbalanced"
Provides-Extra: unsupervised
Requires-Dist: hdbscan>=0.8; extra == "unsupervised"
Requires-Dist: umap-learn>=0.5; extra == "unsupervised"
Provides-Extra: timeseries
Requires-Dist: statsmodels>=0.14; extra == "timeseries"
Requires-Dist: scipy>=1.11; extra == "timeseries"
Requires-Dist: ruptures>=1.1; extra == "timeseries"
Provides-Extra: timeseries-prophet
Requires-Dist: buildml[timeseries]; extra == "timeseries-prophet"
Requires-Dist: prophet>=1.1; extra == "timeseries-prophet"
Provides-Extra: timeseries-ml
Requires-Dist: buildml[timeseries]; extra == "timeseries-ml"
Requires-Dist: neuralforecast>=1.7; python_version < "3.13" and extra == "timeseries-ml"
Requires-Dist: torch>=2.2; extra == "timeseries-ml"
Provides-Extra: anomaly-industry
Requires-Dist: pyod>=1.1; extra == "anomaly-industry"
Requires-Dist: lightgbm>=4.0; extra == "anomaly-industry"
Requires-Dist: xgboost>=2.0; extra == "anomaly-industry"
Provides-Extra: activelearning-industry
Requires-Dist: scikit-activeml>=1.0.0; extra == "activelearning-industry"
Provides-Extra: semisupervised-industry
Requires-Dist: lightgbm>=4.0; extra == "semisupervised-industry"
Requires-Dist: xgboost>=2.0; extra == "semisupervised-industry"
Provides-Extra: ranking-industry
Requires-Dist: lightgbm>=4.0; extra == "ranking-industry"
Requires-Dist: xgboost>=2.0; extra == "ranking-industry"
Requires-Dist: catboost>=1.2; extra == "ranking-industry"
Provides-Extra: metalearning-industry
Requires-Dist: learn2learn>=0.2; python_version < "3.13" and extra == "metalearning-industry"
Provides-Extra: multitask-industry
Requires-Dist: lightgbm>=4.0; extra == "multitask-industry"
Requires-Dist: xgboost>=2.0; extra == "multitask-industry"
Requires-Dist: catboost>=1.2; extra == "multitask-industry"
Provides-Extra: online-industry
Requires-Dist: river>=0.21; extra == "online-industry"
Provides-Extra: recommenders-industry
Requires-Dist: implicit>=0.7; extra == "recommenders-industry"
Provides-Extra: recommenders-lightfm
Requires-Dist: lightfm>=1.17; (python_version < "3.13" and sys_platform != "win32") and extra == "recommenders-lightfm"
Provides-Extra: causal-industry
Requires-Dist: dowhy>=0.11; extra == "causal-industry"
Requires-Dist: econml>=0.15; extra == "causal-industry"
Provides-Extra: federated-industry
Requires-Dist: flwr>=1.5; extra == "federated-industry"
Provides-Extra: kg-industry
Requires-Dist: pykeen>=1.10; extra == "kg-industry"
Provides-Extra: probabilistic-industry
Requires-Dist: mapie>=0.8; extra == "probabilistic-industry"
Requires-Dist: ngboost>=0.5; extra == "probabilistic-industry"
Provides-Extra: symbolic-industry
Requires-Dist: skope-rules>=1.0; python_version < "3.13" and extra == "symbolic-industry"
Requires-Dist: imodels>=2.0; extra == "symbolic-industry"
Requires-Dist: z3-solver>=4.12; extra == "symbolic-industry"
Provides-Extra: cbr-industry
Requires-Dist: hnswlib>=0.8; extra == "cbr-industry"
Provides-Extra: shap
Requires-Dist: shap>=0.44; extra == "shap"
Provides-Extra: nlp
Requires-Dist: nltk>=3.8; extra == "nlp"
Requires-Dist: langdetect>=1.0.9; extra == "nlp"
Requires-Dist: sentence-transformers>=2.2; extra == "nlp"
Requires-Dist: transformers>=4.36; extra == "nlp"
Provides-Extra: nlp-industry
Requires-Dist: buildml[nlp]; extra == "nlp-industry"
Requires-Dist: spacy>=3.7; extra == "nlp-industry"
Provides-Extra: optimize-industry
Requires-Dist: pulp>=2.7; extra == "optimize-industry"
Requires-Dist: ortools>=9.8; extra == "optimize-industry"
Requires-Dist: cvxpy>=1.4; extra == "optimize-industry"
Requires-Dist: xgboost>=2.0; extra == "optimize-industry"
Provides-Extra: synthetic-industry
Requires-Dist: sdv>=1.17; extra == "synthetic-industry"
Requires-Dist: sdmetrics>=0.15; extra == "synthetic-industry"
Provides-Extra: production
Requires-Dist: buildml[torch]; extra == "production"
Requires-Dist: buildml[ssl]; extra == "production"
Requires-Dist: buildml[rag]; extra == "production"
Requires-Dist: buildml[rag-advanced]; extra == "production"
Requires-Dist: buildml[tda]; extra == "production"
Requires-Dist: buildml[unsupervised]; extra == "production"
Requires-Dist: buildml[timeseries]; extra == "production"
Requires-Dist: buildml[timeseries-prophet]; extra == "production"
Requires-Dist: buildml[timeseries-ml]; extra == "production"
Requires-Dist: buildml[graph]; extra == "production"
Requires-Dist: buildml[graph-pyg]; extra == "production"
Requires-Dist: buildml[optuna]; extra == "production"
Requires-Dist: buildml[automl]; extra == "production"
Requires-Dist: buildml[automl-industry]; extra == "production"
Requires-Dist: buildml[tda-industry]; extra == "production"
Requires-Dist: buildml[anomaly-industry]; extra == "production"
Requires-Dist: buildml[semisupervised-industry]; extra == "production"
Requires-Dist: buildml[ranking-industry]; extra == "production"
Requires-Dist: buildml[multitask-industry]; extra == "production"
Requires-Dist: buildml[activelearning-industry]; extra == "production"
Requires-Dist: buildml[metalearning-industry]; extra == "production"
Requires-Dist: buildml[online-industry]; extra == "production"
Requires-Dist: buildml[recommenders-industry]; extra == "production"
Requires-Dist: buildml[recommenders-lightfm]; extra == "production"
Requires-Dist: buildml[causal-industry]; extra == "production"
Requires-Dist: buildml[federated-industry]; extra == "production"
Requires-Dist: buildml[kg-industry]; extra == "production"
Requires-Dist: buildml[probabilistic-industry]; extra == "production"
Requires-Dist: buildml[symbolic-industry]; extra == "production"
Requires-Dist: buildml[cbr-industry]; extra == "production"
Requires-Dist: buildml[nlp]; extra == "production"
Requires-Dist: buildml[nlp-industry]; extra == "production"
Requires-Dist: buildml[optimize-industry]; extra == "production"
Requires-Dist: buildml[synthetic-industry]; extra == "production"
Requires-Dist: buildml[rl]; extra == "production"
Requires-Dist: buildml[rl-industry]; extra == "production"
Provides-Extra: viz
Requires-Dist: matplotlib>=3.7; extra == "viz"
Requires-Dist: seaborn>=0.13; extra == "viz"
Provides-Extra: reports
Requires-Dist: sweetviz>=2.3; extra == "reports"
Requires-Dist: ydata-profiling>=4.6; extra == "reports"
Provides-Extra: eda
Requires-Dist: buildml[reports,viz]; extra == "eda"
Provides-Extra: serve
Requires-Dist: fastapi>=0.110; extra == "serve"
Requires-Dist: uvicorn[standard]>=0.27; extra == "serve"
Requires-Dist: python-multipart>=0.0.9; extra == "serve"
Requires-Dist: httpx>=0.27; extra == "serve"
Requires-Dist: pyyaml>=6.0; extra == "serve"
Provides-Extra: dashboard
Requires-Dist: fastapi>=0.110; extra == "dashboard"
Requires-Dist: uvicorn[standard]>=0.27; extra == "dashboard"
Requires-Dist: plotly>=5.18; extra == "dashboard"
Requires-Dist: kaleido>=0.2.1; extra == "dashboard"
Requires-Dist: reportlab>=4.0; extra == "dashboard"
Requires-Dist: jinja2>=3.1; extra == "dashboard"
Requires-Dist: python-multipart>=0.0.9; extra == "dashboard"
Provides-Extra: excel
Requires-Dist: openpyxl>=3.1; extra == "excel"
Provides-Extra: all-classical
Requires-Dist: buildml[automl,dashboard,eda,engines,excel,imbalanced,optuna]; extra == "all-classical"
Provides-Extra: docs
Requires-Dist: sphinx; extra == "docs"
Requires-Dist: sphinx-rtd-theme; extra == "docs"
Requires-Dist: myst-parser; extra == "docs"
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-cov>=4.1; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Requires-Dist: mypy>=1.8; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: pandas-stubs>=2.0; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: sphinx; extra == "dev"
Requires-Dist: sphinx-rtd-theme; extra == "dev"
Requires-Dist: myst-parser; extra == "dev"
Requires-Dist: buildml[dashboard]; extra == "dev"
Dynamic: license-file

# BuildML

BuildML is a Python library for machine-learning workflows built around a
stateful `Session`. The Session holds the dataset, column roles,
train/validation/test membership, fitted preprocessing plans, an optional
estimator, and a record of every operation you run. Preprocessing learns from
the training partition only; validation and test rows receive frozen
transformations. That train-only boundary is enforced in the API.

**BuildML 2.4 alpha** (`2.4.0a3`) is pre-release software. Public methods, report
schemas, and serialized bundle formats may change before a stable 2.x release.
The public 2.x entry point is `buildml.Session`. For domains, **namespaced
facades** (`session.<domain>.*`) are the supported public API; flat domain
aliases are supported-but-deprecated until BuildML 3.0.

| Path | What it is |
| --- | --- |
| Classical tabular | Main path: ingest → roles → split → preprocess → fit → evaluate |
| Torch DL | Optional multimodal / speech / vision extras on the same Session |
| RAG | Optional retrieve → generate → evaluate |
| AI operator | Optional LLM-assisted plan/execute with allowlists |
| Industry backends | Optional extras + capability matrices per domain |

---

## Install

**Python 3.10–3.13.**

> **Install honesty:** PyPI `buildml` is still the legacy **1.x** line
> (`1.0.9`, MIT). It does **not** install Session 2.x. This checkout is
> release-ready as **`2.4.0a3`**; publishing needs human PyPI ownership / OIDC
> (see [`docs/pypi-2x-publish.md`](docs/pypi-2x-publish.md)). Until that wheel
> is live, install from GitHub or an editable checkout:

```bash
# GitHub (Session 2.x)
pip install "git+https://github.com/TechLeo-Libraries/BuildML.git"

# Editable source checkout (recommended for development / proofs)
pip install -e ".[dev]"
```

### Optional extras (scannable)

| Extra | Install | Adds |
| --- | --- | --- |
| Viz / EDA | `buildml[viz]`, `[reports]`, `[eda]`, `[dashboard]` | matplotlib/seaborn; Sweetviz/profiling; local EDA app |
| Engines | `buildml[engines]` | Polars + DuckDB adapters |
| Search / AutoML | `buildml[optuna]`, `[automl]`, `[automl-industry]` | Optuna; native AutoML; FLAML / AutoGluon / GBDT families |
| Imbalance | `buildml[imbalanced]` | imbalanced-learn resample |
| Torch / DL | `buildml[torch]` / `[dl]` / `[audio]` | Tabular + multimodal Torch path |
| Speech / Vision | `buildml[speech]`, `[vision]`, `[pretrained]` | ASR + finetune-lite; torchvision backbones |
| Serve / ONNX | `buildml[serve]`, `[onnx]` | Local FastAPI serve; ONNX checker |
| RAG | `buildml[rag]`, `[rag-advanced]` | Dense/rerank backends; LangChain hooks |
| Graph / RL / TDA | `buildml[graph]`, `[graph-pyg]`, `[rl]`, `[rl-industry]`, `[tda]` | NetworkX / PyG; Gymnasium / SB3; ripser/persim |
| AI | `buildml[ai]` / `[llm]` | LLM operator (BYO API key) |
| Classical bundle | `buildml[all-classical]` | engines + imbalanced + eda + excel + dashboard + optuna + automl |
| Industry meta | `buildml[production]` | R1–R6 industry extras: **best-effort** (see below) |

```bash
pip install "buildml[production]"   # after GitHub / editable install above
```

### `buildml[production]` honesty

Industry domains ship with capability matrices, backend routing, benchmark
smokes, and guides. `buildml[production]` is a **best-effort** meta-extra: it
pulls domain depth plus `*-industry` adapters. It is **not** a guarantee that
every nested industry wheel installs on every platform.

On **Python 3.13** (especially Windows) some nested pins are skipped via
environment markers when upstream wheels are missing or broken (LightFM,
learn2learn/qpth, giotto-tda, neuralforecast, skope-rules, …). Core sklearn paths
and markers that resolve still install. Check each domain’s capability matrix
(e.g. `session.automl.capability_matrix()`) and the [proof suite](proofs/README.md)
for what actually runs in your environment. For a machine-local inventory of
importable industry modules (never a hard fail), run:

```bash
python scripts/probe_industry_extras.py
```

It does **not** include dashboard, serve, or AI operator extras.

### Security notes (bundles + AI)

- **Pickle / joblib / torch bundles (opt-in).** Checkpoint `plans.joblib`,
  pipeline bundles, domain `*_plan.joblib`, and Torch trainer / TorchScript
  payloads can execute code on load. Public loaders default to `trusted=False`
  and raise `ValidationError` until you pass `trusted=True` for artifacts you
  created or fully trust: for example `Session.checkpoint_load(path, trusted=True)`,
  `session.anomaly.load_bundle(path, trusted=True)`,
  `Session().predict_from_pipeline(path, frame, trusted=True)`, or
  `buildml-serve --bundle … --trusted`. Prefer JSON sidecars / parquet /
  `Session.checkpoint_load(..., data_only=True)` (skips plans without needing
  `trusted`) or re-fitting when provenance is unclear. Optional `sha256`
  integrity in manifests detects *tampering after save*; it does **not** make a
  malicious author safe. **Residual risk:** `trusted=True` on an
  attacker-controlled artifact still executes code: untrusted pickle cannot be
  made safe.
- **AI operator.** Prompt-injection heuristics in `buildml.ai.security` are a
  best-effort layer (NFKC + zero-width / bidi strip, Latin-homoglyph fold,
  multi-line / base64-ish smuggle patterns, structured `InjectionFinding`
  reason codes). Primary controls remain the closed tool registry (runtime
  `register` refused), confirm-on-write for mutating tools, and egress levels in
  `buildml.ai.privacy`. **Residual risk:** paraphrase / novel attacks may
  bypass heuristics: do not treat pattern matching as injection-proof.

---

## A classical workflow

**Facades are the supported public API for domains** in 2.4.x
(`session.fairness.*`, `session.anomaly.*`, …). Flat domain aliases still work
but emit `DeprecationWarning` until BuildML 3.0. Classical core is dual on
purpose: flat `session.fit` / `session.evaluate` / … stay first-class without
warnings, and `session.classical.*` / `session.data.*` / `session.preprocess.*`
are equivalent paths — not a secondary API. See
[`docs/session-facade-migration.md`](docs/session-facade-migration.md).

```python
import pandas as pd
from sklearn.linear_model import LogisticRegression

from buildml import Session

frame = pd.DataFrame(
    {
        "age": [21, None, 35, 40, 29, 33, 52, 47],
        "income": [40, 55, 60, 80, 50, 70, 90, 65],
        "approved": [0, 1, 0, 1, 0, 1, 1, 0],
    }
)

session = Session.ingest(frame)
session.set_roles(
    {"age": "feature", "income": "feature", "approved": "target"}
)
session.split(test_size=0.25, stratify=True, random_state=42)

# Fit on train; apply frozen transforms everywhere else.
# Default impute/encode/scale touch feature-role columns only :
# ignore / id / target / group / time / weight stay unmutated
# (pass columns=[...] to force-include).
session.impute(strategy="median")
session.handle_outliers(method="iqr", action="cap")
session.scale(method="standard")
session.fit(LogisticRegression(max_iter=500), task="classification")

result = session.evaluate(partition="test")
print(result.metrics)
```

When rows are not exchangeable, use `group_split`, `time_split`, or
`inject_split` with memberships you designed outside BuildML.

Cross-validation and hyperparameter search draw folds from the **training**
partition only. The Session test holdout is not used for ranking.

```python
from sklearn.tree import DecisionTreeClassifier
from buildml.preprocess import PreprocessRecipe

cv = session.cv_score(
    LogisticRegression(max_iter=500),
    cv=5,
    preprocess=PreprocessRecipe(impute="median", scale="standard"),
)
print(cv.mean_metrics, cv.std_metrics)

search = session.grid_search(
    DecisionTreeClassifier(random_state=0),
    param_grid={"max_depth": [2, 4, 6], "min_samples_leaf": [1, 5]},
    cv=5,
)
print(search.best_params, search.best_score)
```

Pass a `PreprocessRecipe` when encoding, binning, feature selection, or outlier
fences should be refit inside each fold: on **unpoisoned** data (no prior
Session-global impute/encode/scale). Opt in only with
`allow_session_global_preprocess=True` when you intentionally accept leakage-biased
scores, or re-ingest / checkpoint-load unpoisoned data first.

---

## Artifacts and inspection

```python
session.checkpoint_save("artifacts/checkpoint")
restored = Session.checkpoint_load("artifacts/checkpoint")

session.save_pipeline("artifacts/pipeline", evaluate_partition="test")
loaded = Session.ingest(frame).load_pipeline("artifacts/pipeline")
loaded.apply_preprocess_plans()

before = session.explain("scale", moment="before")
steps = session.workflow()
walkthrough = session.walkthrough(export_html="artifacts/workflow.html")
```

Checkpoints store data workflow state. Model and pipeline bundles store fitted
estimators and preprocess plans: they do not embed each other.
`workflow()` marks operations as done / available / blocked / skipped from API
prerequisites; it does not judge domain fit.

---

## Learning while you work

Every operation and concept is written for three reading levels. `beginner` is
the default and assumes **no** prior machine-learning vocabulary: plain-language
summary, an analogy, the steps in order, what each parameter means in practice,
the pitfalls, and a glossary of the terms the answer itself used.

```python
before = session.explain("split")          # level="beginner" by default
print(before.beginner.plain_summary)
print(before.beginner.analogy)
for step in before.beginner.steps:
    print("-", step)
for knob in before.beginner.key_parameters:
    print(knob.name, "→", knob.plain_meaning, "|", knob.typical_choice)

session.explain("split", moment="after")   # what it did, in this session
session.explain("split", level="advanced") # same facts, no hand-holding
```

`explain` is about **this session right now**: what is missing, what changed,
how to read the result. When the question is conceptual instead, use `learn`,
which takes a concept key, an operation name, or whatever word tripped you up:

```python
session.learn()                    # where to start, in reading order
session.learn("leakage")           # a term → the concept that teaches it
session.learn("stratified")        # spelling/punctuation is forgiving
brief = session.learn("data-splitting")
[note.key for note in brief.read_first]   # read these before this one
[note.key for note in brief.read_next]    # read these once it lands
```

| Level | Shows |
| --- | --- |
| `beginner` | Analogy, plain steps, in-line glossary, worked example |
| `intermediate` | Same facts, less scaffolding, more parameters |
| `advanced` | Full assumptions / leakage / failure lists, no glossary |

The same material backs `Session.explain`, `Session.learn`, `workflow()`,
`walkthrough()`, and the AI operator's `explain_operation` / `learn_concept`
tools, so no surface can drift from another. Teaching content explains ideas and
BuildML's contract; it does not inspect your data or certify that a choice is
appropriate for it.

---

## EDA and reports

```python
session.eda(export_html="artifacts/eda.html")

# pip install "buildml[dashboard]"
handle = session.eda_app(port=8765)
# handle.url -> http://127.0.0.1:8765/

session.evaluate(
    partition="test",
    include_plots=True,
    export_html="artifacts/evaluation.html",
)
```

Reports surface screening evidence. They do not establish causality, fairness,
or deployment readiness on their own. Deeper classical topics (target encoding,
PCA, calibration, learning curves, permutation importance) live in the
[classical quickstart](guides/quickstart-classical.md) and
[workflow guide](docs/workflow-guide.rst).

---

## Domains at a glance

Core `import buildml` stays light (numpy, pandas, scikit-learn). Domain methods
attach to the same Session; classical `fit` / `evaluate` stay unchanged. Each
refined domain exposes an honest **capability matrix** reporting which backends
are installed.

| Area | Guide | Notes |
| --- | --- | --- |
| Classical | [quickstart-classical](guides/quickstart-classical.md) | Roles, splits, preprocess, fit, CV/search |
| Unsupervised / ensembles | [unsupervised](guides/quickstart-unsupervised.md), [ensemble](guides/quickstart-ensemble.md) | Core clustering + voting/stacking |
| AutoML | [automl](guides/quickstart-automl.md) | Native + Optuna; FLAML/AutoGluon via industry |
| Forecast | [forecasting](guides/quickstart-forecasting.md) | `time_split` lags/baselines |
| Time-series analysis | [timeseries-analysis](guides/quickstart-timeseries-analysis.md) | `session.timeseries.analyze` / decompose / diagnostics (no forecast fit) |
| Anomaly | [anomaly](guides/quickstart-anomaly.md) | IsolationForest / LOF / OCSVM + supervised |
| Semi / SSL / AL / Online | matching quickstarts | sklearn floor; industry/torch deepen |
| Multi-task / Meta / Federated | matching quickstarts | MultiOutput / few-shot / FedAvg sim |
| Probabilistic / Causal | matching quickstarts | Conformal; assumption-declared ATE |
| Graph / Symbolic / CBR | matching quickstarts | NetworkX/Torch/PyG; rules; case memory |
| Recommenders / LTR / KG | matching quickstarts | CF + content; GBDT rankers; TransE-style |
| Optimize / Synthetic / IL+RL | matching quickstarts | Thresholds/knapsack; SDV optional; BC + bandits + tabular Q-learning/SARSA |
| TDA | [tda](guides/quickstart-tda.md) | ripser/persim (`buildml[tda]`) |
| NLP | [nlp](guides/quickstart-nlp.md) | Document classify + token attribution, topics, keyphrases, summaries, entities, sentiment, language, corpus profile; `buildml[nlp]` adds encoders |
| Torch | [torch](guides/quickstart-torch.md) | Tabular / text / image / audio fusion |
| RAG | [rag](guides/quickstart-rag.md) | Hashing default; sentence-transformers optional |
| AI operator | [ai](guides/quickstart-ai.md) | Propose→confirm→execute; allowlisted autonomy |

Torch covers tabular MLP, text/sequence, and multimodal fusion; speech
(`buildml[speech]`) is ASR + finetune-lite: not Whisper-scale FM training from
scratch. RAG defaults to lexical hashing; semantic embeddings and grounded
`session.rag.generate` are first-class when extras resolve. NLP models a text column that
lives on the dataset: document classification and analysis, distinct from RAG
retrieval and from Torch fine-tuning. The AI operator defaults to
propose→confirm→execute: not unconstrained agency.

Full guide index: [`guides/README.md`](guides/README.md).

---

## Proof suite

End-to-end evidence that Session domains work with honest splits and holdout
metrics lives under [`proofs/`](proofs/README.md): **not** smoke tests.

| Tier | Status | Meaning |
| --- | --- | --- |
| A | **62/62** | One deep project per major domain (incl. ensembles + Torch + **REAL_PUBLIC_DATASET** cohort) |
| B | **36/36** | Named products composing multiple Session surfaces |
| C | **58/62** | Same-split industry twin + `comparison.json` (qualitative bar 5-B; real-public cohort may be A-only) |

```bash
# Full harness from repo root
python -m proofs._lib.run_all --tier all

# Single project (synthetic or real public)
python proofs/loan-approval-classical/script.py
python proofs/breast-cancer-classical/script.py
```

Install domain extras as needed before running (editable install preferred):

```bash
pip install -e ".[tda,rl,rag,recommenders-industry,automl-industry]"
# richer backends when wheels resolve:
#   implicit → movie-recs ALS
#   sentence-transformers → support-kb-rag dense embeddings
#   flaml / autogluon.tabular → churn-automl / ledger industry AutoML
```

TDA prefers `pip install -e ".[tda]"`. Gymnasium / SB3 deepen the IL+RL path via
`buildml[rl]` / `buildml[rl-industry]` when wheels resolve. See
[`proofs/README.md`](proofs/README.md) for the inventory, Tier C interpretation,
and re-run instructions.

---

## Alpha status

This is pre-release software. Bundle schema version strings, report layouts,
and method signatures may change before a stable 2.x cut. See
[`docs/stability.md`](docs/stability.md) for the public-surface freeze policy.

Shipped: observational fairness disparity reports (`session.fairness.evaluate`) and
optional SHAP attribution (`explain_shap` via `buildml[shap]`). Still out of
scope: out-of-core sklearn training, legal fairness certification, and
unconstrained LLM agency. Speech ASR defaults to a CI-safe stub backend;
`backend="transformers"` is optional and not Whisper-scale FM training.

See [CHANGELOG.md](CHANGELOG.md) for release notes and
[guides/glossary.md](guides/glossary.md) for BuildML terminology:
`session.learn(term)` covers general machine-learning vocabulary.

---

## Documentation

- [Proof suite](proofs/README.md): Tier A/B/C inventory, harness, Tier C interpretation
- [Guides](guides/README.md): quickstarts (each major domain links its proof) and glossary
- [Concepts](docs/concepts.rst): roles, partitions, train-fitted plans
- [Workflow guide](docs/workflow-guide.rst): ordering, leakage, diagnostics
- [Sphinx docs](docs/index.rst): installation, features, API reference, legacy boundary
- [Changelog](CHANGELOG.md): release notes

---

## BuildML 1.x legacy boundary

BuildML 1.x (`SupervisedLearning` and the old module layout) lives under
`buildml/_legacy/` for reference only. It is not imported from the 2.x package
root. There is no compatibility shim that re-exports 1.x APIs from
`import buildml`.

---

## Author and license

**Leonard Onyiriuba**: [LinkedIn](https://www.linkedin.com/in/chukwubuikem-leonard-onyiriuba/) · leonard.c.onyiriuba@gmail.com

Issues: [GitHub](https://github.com/TechLeo-Libraries/BuildML/issues)

Apache License 2.0.
