Skip to content
Agentmart
Submit a tool

AGENTS.md · statsmodels/statsmodels

AGENTS.md from statsmodels/statsmodels: 312 lines covering Project snapshot, Environment setup, Code style & linting, Docstrings & documentation and more.

Template by statsmodels

IndexedBSD-3-Clause★ 11,710
Write a review

Install

Works with Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code. Read the repository before you give any tool access to your data.

curl -fsSL https://raw.githubusercontent.com/statsmodels/statsmodels/main/AGENTS.md -o AGENTS.md

Read it and adapt it to your project before use.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

The AGENTS.md file that statsmodels/statsmodels (11,709 stars) keeps for coding agents. It has 312 lines in 9 sections: Project snapshot; Environment setup; Code style & linting; Docstrings & documentation; Testing conventions; New estimator / model architecture; Git / commit conventions; Pull requests: the AI disclosure is mandatory; Working in this repo as an agent. Use it as a model for your own project's instructions.

Use cases: prompt-engineering

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

What's in it

An AGENTS.md file: instructions coding agents (Codex, Cursor, Copilot, Gemini CLI and others) read before working in a repo.

For
Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code
Length
312 lines
File
AGENTS.md

Sections

  1. Project snapshot
  2. Environment setup
  3. Code style & linting
  4. Docstrings & documentation
  5. Testing conventions
  6. New estimator / model architecture
  7. Git / commit conventions
  8. Pull requests: the AI disclosure is mandatory
  9. Working in this repo as an agent

First lines (shown under the repo's BSD-3-Clause license)

# AGENTS.md

Guidance for coding agents (and humans) contributing to `statsmodels`. This
file is a practical supplement to [CONTRIBUTING.md](CONTRIBUTING.md) and
the [developer docs](https://www.statsmodels.org/devel/dev/index.html) —
read those too, but treat this as the checklist for "will this actually get
merged."

## Project snapshot

- Pure-Python core with a few Cython extensions (Kalman filter code in
  `statsmodels/tsa/statespace/_*.pyx`, etc.). Most new statistical code is
  pure Python.
- Cython extensions are built via `meson`/`ninja` (see
  `pyproject.toml` `[tool.meson-python]` section). Cython extensions
  are accepted only when the performance gain over pure Python is significant.
- Build backend is `meson-python`; the package is normally developed via an
  **editable install** so pure-Python edits are picked up immediately.
- Target Python: `py310`+ (see `[tool.ruff] target-version` /
  `[tool.black] target-version` in `pyproject.toml`).
- Upstream repo is `statsmodels/statsmodels`; when linking issues/PRs in
  commit messages or docs, link that repo, not a personal fork.
- Ensure features taken from upstream packages, `numpy`, `scipy`, `pandas`, etc.,
  are compatible with the minimum versions in `pyproject.toml` and `requirements.txt`.

## Environment setup

```bash
python -m pip install -r requirements.txt
python -m pip install -r requirements-dev.txt
python -m pip install -e . --no-build-isolation
```

Using an editable install mean changes in both Python and Cython are live
immediately; Cython extensions are rebuilt automatically on import
if the source `.pyx` file is newer than the compiled `.so` or `.dll` file.

## Code style & linting

- Formatting: `ruff` (line-length 88, `py310` target, isort-equivalent import sorting via
  `[tool.ruff.lint.isort]`). Import sections: `future`, `compat`,
  `standard-library`, `third-party`, `first-party`, `local-folder` — with
  `statsmodels.compat` treated as its own `compat` section.
- `ruff check .` must pass when run from the repo root.
- `black` (line-length 88) is acceptable for auto-formatting, but not required.
  Only use `black` to format changes to files, or in new files. Do not use `black` to
  wholesale reformat existing files.
- Comments must be in English. This covers code comments, test comments, and
  docstrings. Do not leave comments in another language in the diff; translate
  them or remove them.

## Docstrings & documentation

- Every public function, class, method, and attribute needs a numpydoc
  docstring (numpy docstring standard, not Google/Sphinx style).
- New public functionality must be:
  1. Exported from the relevant `api.py` if the module has one (e.g. new
     `tsa` models go in `statsmodels/tsa/api.py`, matching how `VAR`,
     `SVAR`, `VARMAX` are exposed there) — burying a new class only inside
     an internal module path is a common reason reviewers bounce a PR.
  2. Added to the Sphinx docs — find the relevant `docs/source/*.rst` file
     (e.g. `docs/source/vector_ar.rst` for VAR-family models) and add an
     `autosummary` entry.
  3. Noted in the current release notes file under `docs/source/release/`
     (currently `version0.15.0.rst` — check for the highest-numbered
     unreleased `versionX.Y.Z.rst`).
- If it's a substantial new feature, an example notebook is strongly encouraged.
  (see the "Add an example" step in `CONTRIBUTING.md`).

### Docstring type conventions

Distilled from a repo-wide numpydoc type-correctness pass (2026-08). These
govern the `Parameters`/`Returns`/`Attributes` *type* field specifically —
apply them whenever writing or reviewing a docstring, not just during a
dedicated cleanup:

- **Verify against the actual code, don't pattern-match.** The most common
  real bug in this codebase's docstrings is a type that describes what
  "sounds right" for the parameter's name rather than what the
  implementation actually does with it (coercion, indexing, arithmetic).
  Read the function body before writing or trusting a type string.
- **`array_like` vs `ndarray` vs `sequence of X`:**
  - `array_like` — the value is coerced (`np.asarray`/`np.array(...)`) and
    then used with real array semantics (arithmetic, broadcasting,
    `.shape`/`.ndim`, or passed into another `array_like`-typed call).
  - `ndarray` — genuinely restricted to an already-constructed numpy array
    (no coercion happens; `.shape`/`.ndim`/fancy-indexing used directly on
    the raw parameter, or a plain list would raise).
  - `sequence of X` (or `list of X` if genuinely list-only) — the value is
    only ever iterated, indexed, or `len()`'d, never given real array
    treatment. Don't default to `array_like` just because a parameter
    accepts "more than a bare `ndarray`" — check which of the three is
    actually true.
  - `Returns`/`Attributes` describe the concrete output/stored type, never
    the `Parameters`-side acceptance convention — a value that's always a
    real `ndarray`/`Series`/`DataFrame` by the time it's returned should
    say so, even if the same name accepts `array_like` as an input.
- **No bracket-subscript container types.** `list[int]`, `array_like[int]`,
  `dict[str, int]`, `tuple[float]` are all wrong — use prose:
  `list of int`, `array_like of int`, `dict of str to int`,
  `tuple of float`.
- **`, optional` is the only default marker.** Every parameter with a
  default ends its type string with `, optional`; don't also write
  `, default: X` or restate the default value in the type field — the
  default belongs in prose, in the description below the type line.
- **Don't write `None or X, optional`** when `None` is just the ordinary
  default sentinel — `, optional` already conveys that `None` is accepted.
  Write plain `X, optional`. Keep the explicit `None or X` form only when
  `None` triggers genuinely different downstream behavior (a distinct code
  path, not just "the code checks `is None`" — check whether it *branches*
  meaningfully).
- **Curly braces `{...}` are for literal value enumerations only**, never
  for type unions — `{int, str}` should be `int or str`. A real string-enum
  parameter (validated with `raise ValueError` against exact literal
  values, e.g. `trend`, `method`) should list the actual accepted values,
  not an approximation. Inside the braces, use plain quoted values with no
  backtick markup: `{"n", "co"}` is correct, `` {``"n"``, ``"co"``} `` is
  wrong (redundant RST markup once the value is already quoted inside
  braces).
- `bool` not `boolean`; `str` not `string`; `callable` not
  `function`/`class`.
- The canonical type string for an RNG-seeding parameter (after the
  `seed`→`rng` migration) is exactly:
  `rng : int, array_like of int, numpy.random.Generator, or numpy.random.RandomState, optional`
  — no `None` in the list (redundant with `, optional`), no curly braces.
  If the parameter actually flows into something narrower (e.g. a legacy
  `scipy` `seed=` kwarg that rejects `array_like of int`), use the
  narrower, verified form instead of the full canonical one.
- Standard numpydoc section headers only: `Parameters`, `Returns`,
  `Yields`, `Raises`, `Warns`, `Other Parameters`, `Attributes`, `Methods`,
  `See Also`, `Notes`, `References`, `Examples`, `Warnings`. Don't invent
  new section names (`Restrictions`, `Column order`, etc.) — fold that
  content into `Notes`. Section-underline length must match the header
  text length exactly (this repo's own docstring tooling expects an exact
  match, not just RST's "underline ≥ header length" minimum).
- Every documented parameter/attribute/return must actually exist in the
  current signature/implementation, and every real parameter should be
  documented — check both directions, since signatures drift out of sync
  with docstrings over time (a stale copy-pasted name from a sibling
  method is a very common real bug, not just a style nit).
- A real, non-docstring bug found while auditing docstrings (dead
  parameters, unused kwargs, wrong operator precedence, etc.) belongs in
  its own `BUG:` commit — don't fold a behavior fix into a `DOC:` commit,
  and don't silently "fix" the docstring to match buggy behavior without
  flagging the underlying bug.

## Testing conventions

- Tests live in a `tests/` subpackage next to the code
  (`statsmodels/<area>/tests/test_*.py`). Reference values from other
  packages (R, Stata, SAS, a prior statsmodels version) go in a sibling
  `tests/results/` directory — document *where* each reference value came
  from and why it might not match exactly.
- The preferred style is pure modern `pytest` with `pytest.mark.parametrize`
  for multiple cases, and `pytest` fixtures for shared setup.
- Avoid `unittest.TestCase` style for new tests.
- Statistical/numerical claims should be validated against an existing
  package or known closed-form result wherever possible (this project
  follows a test-driven-development norm for new models/statistical
  functions) — an internal-consistency-only test suite (e.g. "shape is

Signals

Stars
11,710
Forks
3,646
Open issues
2,610
Last commit (this folder)
Oct 24, 2026 (4 days ago)
Last release
Aug 27, 2026 (2 months ago)

From GitHub (fetched Oct 24, 2026).

Details

License
BSD-3-Clause
First seen
Oct 24, 2026
Last checked
Oct 24, 2026
Cite this page

AGENTS.md · statsmodels/statsmodels. Agent Mart. https://agentmart.dev/templates/statsmodels-statsmodels-agents-md (last updated 2026-10-24)