|
| 1 | +# AGENTS.md — AI Development Guidelines for xCDAT |
| 2 | + |
| 3 | +This file is the canonical, tool-agnostic source of AI development rules for the |
| 4 | +[xCDAT](https://github.com/xCDAT/xcdat) project. Tool-specific files |
| 5 | +(`.github/copilot-instructions.md`, `.claude/CLAUDE.md`) contain concise extracts |
| 6 | +aligned with this document. |
| 7 | + |
| 8 | +## Project Overview |
| 9 | + |
| 10 | +xCDAT (Xarray Climate Data Analysis Tools) is a Python library that extends |
| 11 | +[xarray](https://xarray.dev) for climate data analysis on structured grids. It |
| 12 | +provides spatial/temporal averaging, regridding, bounds handling, and dataset |
| 13 | +I/O with CF-convention support. |
| 14 | + |
| 15 | +See `pyproject.toml` for the minimum supported Python version and all dependency |
| 16 | +constraints. |
| 17 | + |
| 18 | +## Repository Layout |
| 19 | + |
| 20 | +``` |
| 21 | +xcdat/ # Main package source |
| 22 | + axis.py # Coordinate axis utilities |
| 23 | + bounds.py # BoundsAccessor (xarray accessor) |
| 24 | + dataset.py # Dataset I/O (open_dataset, open_mfdataset) |
| 25 | + spatial.py # SpatialAccessor for spatial averaging |
| 26 | + temporal.py # TemporalAccessor for temporal averaging |
| 27 | + mask.py # Masking operations |
| 28 | + regridder/ # Regridding subpackage (xESMF, xgcm, regrid2) |
| 29 | + utils.py # Shared utility functions |
| 30 | + _logger.py # Logger setup |
| 31 | + tutorial.py # Sample data utilities |
| 32 | +tests/ # Pytest test suite (test_*.py) |
| 33 | +docs/ # Sphinx documentation |
| 34 | +conda-env/ # Conda environment files |
| 35 | +``` |
| 36 | + |
| 37 | +## Coding Standards |
| 38 | + |
| 39 | +- **Formatter / Linter**: Ruff — handles formatting, linting, and import sorting. |
| 40 | + See `pyproject.toml` under `[tool.ruff]` for configuration. |
| 41 | +- **Type Checking**: MyPy — all public APIs must include type annotations. |
| 42 | + See `pyproject.toml` under `[tool.mypy]` for configuration. |
| 43 | +- **Docstrings**: Use **NumPy-style** docstrings for all public functions, classes, |
| 44 | + and methods. Include `Parameters`, `Returns`, and `Raises` sections as applicable. |
| 45 | +- **Imports**: Use absolute imports within the package |
| 46 | + (e.g., `from xcdat.axis import get_dim_coords`). Import sorting is handled by Ruff. |
| 47 | +- **Pre-commit**: The project uses pre-commit hooks. See `.pre-commit-config.yaml` |
| 48 | + for the configured checks (Ruff, MyPy, whitespace, etc.). |
| 49 | +- **License**: New contributions must be made under the Apache-2.0 with LLVM exception |
| 50 | + license. |
| 51 | + |
| 52 | +## Architecture |
| 53 | + |
| 54 | +- **xarray Accessors**: `BoundsAccessor`, `SpatialAccessor`, `TemporalAccessor`, and |
| 55 | + `RegridderAccessor` extend `xr.Dataset` via `@xr.register_dataset_accessor`. |
| 56 | + Follow this pattern when adding new dataset-level functionality. |
| 57 | +- **CF Conventions**: Use `cf_xarray` for coordinate discovery. Always reference axes |
| 58 | + by CF standard names or axis attributes, not hardcoded dimension names. |
| 59 | +- **Module Responsibility**: Each module has a single clear responsibility. Avoid |
| 60 | + circular imports. Shared helpers go in `utils.py`. |
| 61 | +- **Public API**: All public symbols are re-exported from `xcdat/__init__.py`. When |
| 62 | + adding a new public function or class, add it to `__init__.py`. |
| 63 | + |
| 64 | +## Testing Conventions |
| 65 | + |
| 66 | +- **Framework**: pytest with pytest-cov. See `pyproject.toml` under |
| 67 | + `[tool.pytest.ini_options]` for configuration. |
| 68 | +- **File Naming**: Test files live in `tests/` and follow the pattern `test_<module>.py`. |
| 69 | +- **Assertions**: Prefer `xarray.testing.assert_identical` and |
| 70 | + `xarray.testing.assert_allclose` for comparing xarray objects. |
| 71 | +- **Fixtures**: Use pytest fixtures for reusable test data. Construct expected results |
| 72 | + explicitly and compare against actual output. |
| 73 | +- **Running Tests**: `pytest` (full suite) or `pytest tests/test_<module>.py` (targeted). |
| 74 | + Use `make test` for the full suite with coverage. |
| 75 | + |
| 76 | +## Dependencies |
| 77 | + |
| 78 | +- See `pyproject.toml` under `[project.dependencies]` for runtime dependencies and |
| 79 | + version constraints. |
| 80 | +- See `pyproject.toml` under `[project.optional-dependencies]` for dev, test, and |
| 81 | + docs dependencies. |
| 82 | +- Do not add new runtime dependencies without discussion. Prefer leveraging existing |
| 83 | + dependencies before introducing new ones. |
| 84 | + |
| 85 | +## Build & Development |
| 86 | + |
| 87 | +```bash |
| 88 | +# Create dev environment |
| 89 | +conda env create -f conda-env/dev.yml |
| 90 | +conda activate xcdat_dev |
| 91 | + |
| 92 | +# Install local build |
| 93 | +make install # or: python -m pip install . |
| 94 | + |
| 95 | +# Quality assurance |
| 96 | +make lint # ruff check + fix |
| 97 | +make format # ruff format |
| 98 | +make pre-commit # run all pre-commit hooks |
| 99 | + |
| 100 | +# Testing |
| 101 | +make test # full suite with coverage |
| 102 | +pytest tests/test_<module>.py # targeted tests |
| 103 | + |
| 104 | +# Documentation |
| 105 | +make docs # build Sphinx HTML docs |
| 106 | +``` |
| 107 | + |
| 108 | +## Workflow Rules |
| 109 | + |
| 110 | +- Always run `pre-commit run --all-files` before committing. |
| 111 | +- Every PR should include tests for new or changed behavior. |
| 112 | +- Do not modify unrelated code or tests. |
| 113 | +- Keep changes minimal and focused on the issue being addressed. |
| 114 | +- Use meaningful commit messages that summarize the change. |
0 commit comments