From 5eb9e3ff90a3c79ccbca6558e8507017d4ca94b4 Mon Sep 17 00:00:00 2001 From: micahpw <6476273+micahpw@users.noreply.github.com> Date: Tue, 4 Aug 2026 11:22:47 -0600 Subject: [PATCH] docs: add AGENTS.md and llms.txt, tighten PyPI discoverability metadata AGENTS.md is contributor-facing (dev setup, lazy-import conventions, release process) so a coding agent working on GAT itself doesn't have to re-derive them from source. llms.txt is end-user-facing, served at the docs site root per the llmstxt.org convention, for agents helping someone consume nlr-gat as a dependency. pyproject.toml gets keywords and richer trove classifiers for PyPI/search discoverability. --- AGENTS.md | 104 ++++++++++++++++++++++++++++++++ docs/source/_llms_root/llms.txt | 40 ++++++++++++ docs/source/conf.py | 4 ++ pyproject.toml | 18 ++++++ 4 files changed, 166 insertions(+) create mode 100644 AGENTS.md create mode 100644 docs/source/_llms_root/llms.txt diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..ee5220f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,104 @@ +# Agent notes for working on GAT + +This file is for coding agents (and humans) *contributing to* GAT itself. +If you're looking for how to *use* GAT as a library, see the +[README](README.md) and the docs site instead — this file is repo-internal. + +## What this is + +GAT (`nlr-gat` on PyPI) is a format-agnostic API over grid-model +simulation outputs (Sienna, PLEXOS, ReEDS), with a thin core and +per-format extras so consumers only install the native-code dependencies +(h5py, duckdb, geopandas, polars, matplotlib) their format actually needs. + +## Layout + +- `src/gat/` — the package (src layout; import as `gat`) +- `src/gat/scenariohandlers/`, `src/gat/simulations/`, `src/gat/systems/`, + `src/gat/datahelpers/` — package boundaries that use a lazy + `__getattr__` pattern (PEP 562) instead of eager `from .x import *`. + **If you add a new format module here, wire it into the `__getattr__` + dispatch, don't add a blanket import** — that's what keeps + `pip install nlr-gat[reeds]` from pulling in h5py/geopandas/duckdb. +- `docs/source/` — Sphinx docs (MyST markdown + autodoc); built and + deployed to GitHub Pages on push to `main`. +- `tests/` — pytest; regression baselines under `tests/handlers/` use + `pytest-regressions` snapshots. + +## Setup + +```bash +python -m venv .venv && . .venv/bin/activate +pip install -e ".[dev]" +``` + +`dev` is deliberately self-referential (`nlr-gat[sienna,plexos,reeds,plots]`) +so the full test suite is runnable out of the box — see the comment above +it in `pyproject.toml` (issue #23) for why that matters. + +## Running tests + +```bash +make test # pytest tests/ -v +``` + +Some tests need fixture data that isn't checked in: +- **Sienna**: `make sienna-fixture-v4` (needs Docker; see + `docker/sienna/README.md`). Point `GAT_SIENNA_FIXTURE` or use the + default resolution order in `tests/visual/generate_fixture_deck.py` if + working with fixtures interactively. +- **PLEXOS**: set `GAT_PLEXOS_FIXTURE` (H5PLEXOS.jl `.h5` directory) or + `GAT_PLEXOS_ZIP_FIXTURE` (native `Solution.zip`) to point at your own + data. Tests needing fixtures that aren't present skip rather than fail. + +After a change that should shift regression baselines intentionally: + +```bash +make regen-snapshots +``` + +## Conventions + +- **Formatting/lint**: `black` (line length 88) and a minimal `ruff` + rule set (bug-catching only, not style). CI runs + `black --check src/gat tests` and `ruff check src/gat tests`. +- **Commit messages and PR titles must follow [Conventional + Commits](https://www.conventionalcommits.org/)** (`feat:`, `fix:`, + `docs:`, `refactor:`, `perf:`, `ci:`, `build:`, `test:`, `chore:`, + with `!` or a `BREAKING CHANGE:` footer for breaking changes). This is + enforced (informationally, not yet a required check) by + `.github/workflows/commit-lint.yml`, and it's not just style — + **release-please parses these prefixes to compute version bumps and + generate `docs/source/CHANGELOG.md`.** An unprefixed commit is + invisible to it, not an error. +- **No static version string.** GAT uses `setuptools_scm` — version is + derived from git tags at build time (`dynamic = ["version"]` in + `pyproject.toml`). Never hand-edit a version number anywhere. + +## Release process + +Releases are automated via [release-please](https://github.com/googleapis/release-please) +(`.github/workflows/release.yml`), modeled on NatLabRockies/R2X: + +1. Every push to `main` (i.e., every merged PR) updates a standing + `chore(main): release nlr-gat X.Y.Z` PR with an auto-generated + changelog, computed from Conventional Commits since the last release. +2. Merging that PR creates the git tag + GitHub Release. +3. That triggers build + publish to PyPI via Trusted Publishing (OIDC, + no stored token). The `pypi` GitHub Environment has a required + reviewer gate — publishing pauses for manual approval regardless of + who merged the release PR. + +You will not need to run `git tag` or upload to PyPI by hand. + +## Known gotchas worth knowing before you dig for them + +- `EGRETScenario` was removed entirely (issue #11) — if you find a + reference to EGRET in an old branch or issue, it's gone, not moved. +- Support for PLEXOS `.h5` files (from H5PLEXOS.jl) is deprecated as of + v0.1.1 and will be removed in v0.2.0 — new PLEXOS work should target + the DuckDB-backed engine (`nlr-gat[plexos]`, native `Solution.zip`). +- Path arguments (`PlexosScenario(...)`, etc.) go through + `os.path.expanduser()` before resolution — `~` is expanded, but shell + globs and environment variables written literally in a Python string + are not. diff --git a/docs/source/_llms_root/llms.txt b/docs/source/_llms_root/llms.txt new file mode 100644 index 0000000..f4702ab --- /dev/null +++ b/docs/source/_llms_root/llms.txt @@ -0,0 +1,40 @@ +# GAT (Grid Analysis Toolkit) + +> A format-agnostic Python API for reading Production Cost Model (PCM) +> and Capacity Expansion Model (CEM) simulation outputs — Sienna +> (PowerSimulations.jl), PLEXOS, and ReEDS today — into pandas +> DataFrames, without needing to know each format's native file layout. +> Distributed on PyPI as `nlr-gat` (import as `gat`); source at +> https://github.com/NatLabRockies/GridAnalysisToolkit. + +GAT's public API is still evolving pre-1.0 — pin an exact version if you +need stability. The base package installs almost nothing; each simulation +format is an opt-in extra so you only pull in the native-code +dependencies (h5py, duckdb, geopandas, polars) that format needs, e.g. +`pip install "nlr-gat[sienna]"` or `pip install "nlr-gat[plexos,plots]"`. + +## Getting started + +- [Installation and extras table](https://github.com/NatLabRockies/GridAnalysisToolkit#installation): which `pip install "nlr-gat[...]"` extra to use for Sienna, PLEXOS, ReEDS, plotting, server/client, or all of the above +- [Quickstart: scenarios and palettes](scenario_quickstart.html): load a scenario and pull your first dispatch/capacity results +- [Python API: gat.load(...)](python_api_load.html): the top-level entry point for constructing a scenario from a path + +## Format-specific guides + +- [Sienna scaling and raw dataset access](sienna_scaling.html): base-power scaling rules and how to reach unscaled h5 datasets directly +- [Legacy scenario handler deprecation](legacy_handler_deprecation.html): what changed, what's deprecated (H5PLEXOS.jl `.h5` support, removed in v0.2.0), and migration paths + +## Extending GAT + +- [Custom plots and the reporting framework](extending_plots.html): the `@plot_function` decorator and how quickplots/reports are assembled +- [v1 architecture & migration pattern](architecture/v1_migration_pattern.html): the `BaseSystem`/`BaseSimulation` interfaces new format backends implement + +## Reference + +- [Changelog](https://github.com/NatLabRockies/GridAnalysisToolkit/blob/main/docs/source/CHANGELOG.md): version history, generated from Conventional Commits +- [PyPI package](https://pypi.org/project/nlr-gat/) +- [Issue tracker](https://github.com/NatLabRockies/GridAnalysisToolkit/issues) + +## Optional + +- [Migrating from v0.x to v1.0](migration_v1.html): only relevant if you're upgrading an existing integration diff --git a/docs/source/conf.py b/docs/source/conf.py index 29e761b..b5a1242 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -59,6 +59,10 @@ html_theme = "sphinx_book_theme" html_static_path = ["_static"] +# Copied verbatim to the site root (unlike html_static_path, which nests +# under /_static/) so llms.txt is served at the conventional +# https:///llms.txt location — see llmstxt.org. +html_extra_path = ["_llms_root"] source_suffix = { ".rst": "restructuredtext", diff --git a/pyproject.toml b/pyproject.toml index 91ee487..4641148 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,10 +29,28 @@ license = {file = "LICENSE"} authors = [ {name = "Micah Webb", email = "micah.webb@nlr.gov"}, ] +keywords = [ + "power systems", + "grid analysis", + "production cost model", + "capacity expansion model", + "PCM", + "CEM", + "PLEXOS", + "Sienna", + "PowerSimulations.jl", + "ReEDS", + "energy modeling", +] classifiers = [ "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering", ] [project.scripts] gat="gat.cli:cli"