Contributing¶
The full guide lives in CONTRIBUTING.md in the repository. The short version:
Setup¶
git clone https://github.com/DrobyshevDev/mlango
cd mlango
python -m venv .venv && source .venv/bin/activate
pip install -e ".[all]"
pre-commit install
pytest -q
The suite runs offline — agents use the echo provider and the metastore is
SQLite in a temporary directory. No API key is needed to contribute.
Before opening a pull request¶
ruff check mlango tests
ruff format mlango tests
mypy mlango
pytest -q --cov
mkdocs build --strict # if you touched docs
All five are blocking in CI. pytest --cov enforces the same coverage floor
locally that it does on the server — the threshold lives in pyproject.toml, so
there is no way to be green on a laptop and red on CI.
The pipeline¶
.github/workflows/ci.yml (mirrored in .gitlab-ci.yml) runs:
| Job | What it protects |
|---|---|
lint |
ruff, ruff format, mypy with no errors allowed |
test |
the suite on Python 3.10–3.13, plus macOS and Windows |
coverage |
the floor in [tool.coverage.report] fail_under |
audit |
pip-audit against what actually gets installed |
quickstart |
startproject → migrate → train → evaluate → serve, for real |
transformers |
fine-tunes a tiny checkpoint, so that backend is exercised |
build |
wheel installs into a clean venv and ships py.typed |
docs |
mkdocs build --strict |
ci |
one aggregate check that fails if any job above did |
CodeQL runs separately, on pushes and weekly.
Require the aggregate CI check in branch protection rather than the
individual jobs. Requiring them one by one means a job added later is not
required, and a red job silently stops blocking merges.
Two rules for the coverage floor: raise it when the number rises, and never lower it to turn a red build green. If a change genuinely cannot be covered, say why in the pull request.
What we look for¶
Errors that teach. A message should say what went wrong and what to do next:
Comments that explain why, not what. The code says what it does; explain the constraint a reader cannot see.
Tests named after the guarantee they protect —
test_assignment_is_stable_when_rows_are_added, not test_split.
No new required dependencies in the core. Optional integrations go behind an
extra in pyproject.toml with a lazy import.
Layering¶
| Layer | May import | Must not import |
|---|---|---|
core/ |
stdlib only | anything else in mlango |
metastore/ |
core |
data, training, agents |
data/, training/, agents/, evals/ |
core, metastore |
each other |
admin/, serve/ |
everything, through _meta |
— |
If you need a helper across layers, it belongs in core — see
core/serialization.py, which exists for exactly that reason.
Everything generic reads _meta rather than checking concrete types. That is
what lets one admin render datasets, models, agents and evals. If a feature
wants isinstance(obj, Dataset), look for the _meta attribute it should read
instead.
Good first contributions¶
- Translate a documentation page — see Translating
- Improve an error message you found confusing
- Add a scorer to
mlango/evals/scorers.py - Add a trainer backend (a single file plus a settings entry)
- Add a
Sourcefor a format you use
Reporting bugs¶
Include the output of python manage.py check and the smallest declaration that
reproduces the problem.