|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +Instructions for AI assistants and agents working with code in this |
| 4 | +repository. |
| 5 | + |
| 6 | +## Overview |
| 7 | + |
| 8 | +GRASS is a large, multi-language geospatial processing engine. The codebase |
| 9 | +is primarily C (core libraries and tools) and Python (high-level API, scripts, |
| 10 | +GUI, tests). Tools follow a `<type>.<name>` naming convention: `r.*` (raster), |
| 11 | +`v.*` (vector), `g.*` (general), `d.*` (display), `i.*` (imagery), `t.*` |
| 12 | +(temporal), `r3.*` (3D raster). |
| 13 | + |
| 14 | +## Build |
| 15 | + |
| 16 | +On the `main` branch, Autotools and CMake are equivalent. Older release |
| 17 | +branches support Autotools only, and full documentation builds (MkDocs) also |
| 18 | +require Autotools. See `INSTALL.md` for full build instructions including |
| 19 | +dependencies and configuration options. |
| 20 | + |
| 21 | +**Autotools:** |
| 22 | + |
| 23 | +```bash |
| 24 | +CFLAGS="-g -Wall" ./configure # configure with debug flags |
| 25 | +make # compile everything |
| 26 | +make install # install |
| 27 | +make libs # compile libraries only |
| 28 | +``` |
| 29 | + |
| 30 | +**CMake:** |
| 31 | + |
| 32 | +```bash |
| 33 | +cmake -B build |
| 34 | +cmake --build build |
| 35 | +cmake --install build |
| 36 | +``` |
| 37 | + |
| 38 | +**Compile a single tool** (after libraries are built): |
| 39 | + |
| 40 | +```bash |
| 41 | +cd raster/r.slope.aspect |
| 42 | +make |
| 43 | +``` |
| 44 | + |
| 45 | +Build outputs go to `bin.$ARCH/` and `dist.$ARCH/` directories. |
| 46 | + |
| 47 | +## Running Tests |
| 48 | + |
| 49 | +Tests require a built and installed GRASS with the `grass` binary on `PATH`. |
| 50 | +If running from a local build (not a system install), add the binary directory |
| 51 | +to PATH first: |
| 52 | + |
| 53 | +```bash |
| 54 | +export PATH="$(pwd)/bin.$(uname -m)-pc-linux-gnu:${PATH}" |
| 55 | +``` |
| 56 | + |
| 57 | +Before running pytest, set the required environment variables: |
| 58 | + |
| 59 | +```bash |
| 60 | +export PYTHONPATH="$(grass --config python_path):${PYTHONPATH}" |
| 61 | +export LD_LIBRARY_PATH="$(grass --config path)/lib:${LD_LIBRARY_PATH}" |
| 62 | +``` |
| 63 | + |
| 64 | +For coverage reporting, two additional variables are needed (used by |
| 65 | +`.coveragerc` to map paths): |
| 66 | + |
| 67 | +```bash |
| 68 | +export INITIAL_GISBASE="$(grass --config path)" |
| 69 | +export INITIAL_PWD="${PWD}" |
| 70 | +``` |
| 71 | + |
| 72 | +**Run tests for a specific tool:** |
| 73 | + |
| 74 | +```bash |
| 75 | +pytest raster/r.slope.aspect/tests/ |
| 76 | +``` |
| 77 | + |
| 78 | +**Run a single test file:** |
| 79 | + |
| 80 | +```bash |
| 81 | +pytest raster/r.slope.aspect/tests/r_slope_aspect_test.py |
| 82 | +``` |
| 83 | + |
| 84 | +**Run gunittest-style tests** (legacy `testsuite/` directories; currently the |
| 85 | +only way to use larger datasets like the `nc_spm` sample dataset): |
| 86 | + |
| 87 | +```bash |
| 88 | +python -m grass.gunittest.main --grassdata /path/to/grassdata --location location --location-type xyz |
| 89 | +``` |
| 90 | + |
| 91 | +Test files follow two patterns: |
| 92 | + |
| 93 | +- `*/tests/*_test.py` or `*/tests/test_*.py` — pytest style (preferred for new tests) |
| 94 | +- `*/testsuite/` directories — gunittest style (slightly less preferred, but |
| 95 | + required when tests need large external datasets) |
| 96 | + |
| 97 | +pytest configuration is in `pyproject.toml`. pytest tests require a running |
| 98 | +GRASS session with a project/mapset; see |
| 99 | +`raster/r.slope.aspect/tests/conftest.py` for a representative session |
| 100 | +fixture. For new pytest tests, use `grass.tools` with `Tools`: the `Tools` |
| 101 | +object needs `session=session` (or `env=session.env`) at creation, but |
| 102 | +individual tool calls do not need `env`. When using `grass.script` in |
| 103 | +pytest, every call (`gs.run_command()`, `gs.parse_command()`, etc.) must |
| 104 | +pass `env=session.env` explicitly. gunittest-style tests (`testsuite/`) run |
| 105 | +in an existing GRASS session and need neither `Tools` setup nor `env` |
| 106 | +passing. |
| 107 | + |
| 108 | +## Linting and Formatting |
| 109 | + |
| 110 | +See `doc/development/style_guide.md` for full formatting and style rules. |
| 111 | +Quick reference: |
| 112 | + |
| 113 | +```bash |
| 114 | +pre-commit run --all-files # run all checks |
| 115 | +``` |
| 116 | + |
| 117 | +## Architecture |
| 118 | + |
| 119 | +### Core Libraries (`lib/`) |
| 120 | + |
| 121 | +C libraries linked by tools. Key ones: |
| 122 | + |
| 123 | +- `lib/gis/` — coordinate systems, map management, environment (`libgis`) |
| 124 | +- `lib/raster/` — raster I/O |
| 125 | +- `lib/vector/` — vector topology and I/O |
| 126 | +- `lib/db/` — database drivers (SQLite, PostgreSQL, etc.) |
| 127 | +- `lib/imagery/` — imagery/classification routines |
| 128 | +- `lib/temporal/` — time series framework support |
| 129 | + |
| 130 | +### Python API (`python/grass/`) |
| 131 | + |
| 132 | +Four primary packages: |
| 133 | + |
| 134 | +- `grass.script` — procedural interface; wraps GRASS tools via `run_command`, |
| 135 | + `parse_command`, `read_command`, etc. Import as `import grass.script as gs`. |
| 136 | + Use this in `grass.script` itself and code that `grass.script` depends on. |
| 137 | +- `grass.tools` — preferred interface for new code and new tests; provides a |
| 138 | + `Tools` class with direct Python attribute access to GRASS tools (e.g., |
| 139 | + `tools.r_slope_aspect(...)`). Most existing code uses `grass.script` |
| 140 | + (`gs.run_command()` etc.), so expect to see both. Do not use `grass.tools` |
| 141 | + in `grass.script` or anything `grass.script` depends on (circular |
| 142 | + dependency). Not to be confused with the object-oriented API of |
| 143 | + `grass.pygrass`. |
| 144 | +- `grass.pygrass` — object-oriented API; provides `Raster`, `Vector` classes |
| 145 | + and a lower-level module interface |
| 146 | +- `grass.temporal` — space-time dataset (STRDS/STVDS) management. Import as |
| 147 | + `import grass.temporal as tgis`. |
| 148 | + |
| 149 | +### Tool Structure |
| 150 | + |
| 151 | +Each tool (e.g., `raster/r.slope.aspect/`) contains: |
| 152 | + |
| 153 | +- `main.c` (or `<name>.py` for Python scripts) — entry point |
| 154 | +- `Makefile` — follows a standard template; see |
| 155 | + `raster/r.slope.aspect/Makefile` (C tool) and `scripts/r.mask/Makefile` |
| 156 | + (Python script) for examples |
| 157 | +- `CMakeLists.txt` — CMake build definition; see |
| 158 | + `raster/r.colors.out/CMakeLists.txt` for an example |
| 159 | +- `<name>.md` — documentation source (no header/footer; Markdown rendered by |
| 160 | + MkDocs) |
| 161 | +- `<name>.html` — supports a legacy documentation system; uses HTML markup |
| 162 | + for formatting but is not a complete HTML document (only the translated |
| 163 | + Markdown into corresponding HTML tags). Must be committed alongside the |
| 164 | + `.md` file. |
| 165 | +- `tests/` — pytest tests |
| 166 | +- `testsuite/` — gunittest tests (legacy) |
| 167 | + |
| 168 | +### Python Scripts (`scripts/`) |
| 169 | + |
| 170 | +Python-based tools (e.g., `scripts/r.mask/`) use `grass.script` and |
| 171 | +`g.parser` for option parsing. They follow the same tool structure as C tools. |
| 172 | + |
| 173 | +### GUI (`gui/wxpython/`) |
| 174 | + |
| 175 | +wxPython desktop application. The GUI uses tools and libraries (Python and |
| 176 | +C) to do geospatial and data work, so anything available in the GUI can |
| 177 | +also be done with tools, the command line, or the Python and C APIs. Other |
| 178 | +code should not depend on the GUI at runtime or during compilation, except |
| 179 | +for unavoidable cases like starting the GUI from the command line. For |
| 180 | +classes and code that inherit from wxPython classes or use their interface, |
| 181 | +wxPython conventions are used rather than standard GRASS Python conventions. |
| 182 | + |
| 183 | +## Key Coding Conventions |
| 184 | + |
| 185 | +For full conventions, see `doc/development/style_guide.md`. The following |
| 186 | +highlights rules that are especially important or easy for AI agents to |
| 187 | +miss. |
| 188 | + |
| 189 | +### Comments (all languages) |
| 190 | + |
| 191 | +- No decorative comment banners or dividers (e.g., `# ---- Section ----`). |
| 192 | +- No double space after a sentence-ending period. |
| 193 | +- Write full sentences with proper capitalization, not stubs or all-lowercase |
| 194 | + fragments. |
| 195 | +- Do not restate what the code already says; comment on intent, rationale, |
| 196 | + or non-obvious behavior. |
| 197 | +- Strongly prefer plain ASCII for comments; use Unicode only when necessary. |
| 198 | + For Python docstrings and Doxygen comments, plain ASCII is still preferred |
| 199 | + but Unicode is more acceptable. |
| 200 | +- Inline comments in code examples must be separated from code by exactly |
| 201 | + two spaces (e.g., `x = 1 # comment`). |
| 202 | + |
| 203 | +### Tests |
| 204 | + |
| 205 | +- Module-level globals in test files do not need a leading underscore; test |
| 206 | + modules are not public APIs. |
| 207 | + |
| 208 | +### Python |
| 209 | + |
| 210 | +- Import `grass.script` as `gs` (enforced by ruff `ICN001` rule) |
| 211 | +- Import `grass.temporal` as `tgis` |
| 212 | +- Use `str.format()` for translatable user messages (not f-strings): |
| 213 | + `gs.warning(_("Map <{}> not found.").format(name))` |
| 214 | +- Use f-strings for non-translatable strings |
| 215 | +- In tool code (not Python libraries): use `gs.fatal()` to exit with error, |
| 216 | + `gs.warning()` for warnings, `gs.message()` for informational output. |
| 217 | + Use `print()` only for text data output (e.g., results the user pipes |
| 218 | + elsewhere); never for messages to the user. |
| 219 | +- Data is organized in **projects** (formerly called "locations") and mapsets |
| 220 | + |
| 221 | +### C |
| 222 | + |
| 223 | +- Use `G_malloc()`, `G_calloc()`, `G_free()` instead of standard C equivalents |
| 224 | +- Use `G_fatal_error()`, `G_warning()`, `G_message()` for output |
| 225 | +- Use `EXIT_SUCCESS`/`EXIT_FAILURE` return values from `main()` |
| 226 | +- Include order: system headers, then non-core system libs, then GRASS headers |
| 227 | + (`grass/gis.h`, etc.), then local headers; groups alphabetically sorted, |
| 228 | + separated by blank lines |
| 229 | +- Snake case for function names (GNU naming convention) |
| 230 | + |
| 231 | +### Documentation (tool doc files) |
| 232 | + |
| 233 | +Each tool must have both `<tool>.md` and `<tool>.html` committed to the |
| 234 | +repository. The `.md` is the source of truth; the `.html` provides basic HTML |
| 235 | +access and must be kept in sync. See `doc/development/style_guide.md` for |
| 236 | +full markup conventions. |
| 237 | + |
| 238 | +Required sections in the `.md`: `## DESCRIPTION`, `## SEE ALSO`, `## AUTHORS` |
| 239 | +Suggested: `## NOTES`, `## EXAMPLES` |
| 240 | + |
| 241 | +Markup conventions: |
| 242 | + |
| 243 | +- Tool names in italic: `*r.slope.aspect*` |
| 244 | +- Flags and parameter names in bold: `**-f**`, `**input**` |
| 245 | +- Values, paths, commands in backticks |
| 246 | +- `SEE ALSO` section alphabetized |
| 247 | + |
| 248 | +### Tool Interface |
| 249 | + |
| 250 | +Tools must use the GRASS parser for parameters. Use standard options |
| 251 | +(`G_OPT_R_INPUT`, `G_OPT_V_OUTPUT`, etc.) instead of defining common |
| 252 | +parameters from scratch. The full list of standard options is generated from |
| 253 | +`lib/gis/parser_standard_options.c`. Prefer a `format` option over multiple exclusive |
| 254 | +flags for output format selection. Output must always go to the current |
| 255 | +mapset. Tools must not overwrite existing maps unless the user provides |
| 256 | +`--overwrite`. |
| 257 | + |
| 258 | +Tool name prefixes: `r.` (raster), `v.` (vector), `g.` (general), `d.` |
| 259 | +(display), `i.` (imagery), `t.` (temporal), `r3.` (3D raster), `db.` |
| 260 | +(database), `m.` (miscellaneous), `ps.` (PostScript). |
| 261 | + |
| 262 | +## Commit Messages |
| 263 | + |
| 264 | +See `doc/development/github_guide.md` for the full Git workflow. Commit |
| 265 | +message rules: |
| 266 | + |
| 267 | +- Start with a prefix matching the category regexps in `utils/release.yml` |
| 268 | + (e.g., `r.slope.aspect:`, `grass.script:`, `CI:`) |
| 269 | +- After the prefix, start with a capital letter — unless the first word is an |
| 270 | + identifier that is conventionally lowercase (e.g., `r.info` or `gs`) |
| 271 | +- Use plain ASCII only, no double spaces after periods |
| 272 | +- Write in imperative mood (e.g., "Add support for X", not "Added" or "Adds") |
| 273 | +- Do not add AI co-authors; the human author is responsible for the code. |
| 274 | + However, larger use of AI should be acknowledged in the commit message |
| 275 | + and/or PR description, similarly to how a book or a discussion with a |
| 276 | + human collaborator would be acknowledged. |
| 277 | + |
| 278 | +## AI Use Policy |
| 279 | + |
| 280 | +See `CONTRIBUTING.md` for the full AI use policy. Key points: AI-assisted |
| 281 | +development is acceptable, but contributors must test all code, understand |
| 282 | +their submissions, and disclose AI assistance when substantial algorithms |
| 283 | +or logic were AI-generated. |
0 commit comments