Skip to content

Commit 4d5f514

Browse files
authored
contributing: Add AGENTS.md with guidelines for AI agents (#7110)
Adds instructions for AI coding agents in general (somewhat standardized AGENTS.md in the top dir) and Claude Code specific file linking it. This should improve the quality of the code and commits generated by agents/tools which have access to the repository code. I developed that during test creation (for pytest) and during the work on the file itself, so probably more is needed for Python and C tools, GUI, grass.gunittest tests. I then tried to optimize what is in the new file versus what is already elsewhere to minimize duplication (maybe we eventually want to cover some of these items in the other documentation). It now references a lot of existing files which likely increases the computational cost. Comments on use of AI and references CONTRIBUTING.md AI use policy. For (local) linting, only pre-commit is used. Also pytest run of all test is left for the CI.
1 parent d09c9ce commit 4d5f514

File tree

2 files changed

+286
-0
lines changed

2 files changed

+286
-0
lines changed

.claude/CLAUDE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# CLAUDE.md
2+
3+
@../../AGENTS.md

AGENTS.md

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
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

Comments
 (0)