diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..285469a8c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,145 @@ +# NumericalEarth.jl — Agent Rules + +## Project Overview + +NumericalEarth.jl provides infrastructure for running Earth system model components—ocean, atmosphere, sea ice, and others—coupled together or driven by prescribed datasets. The coupling interface is generic: plug in [Oceananigans.jl](https://github.com/CliMA/Oceananigans.jl) for ocean dynamics, [ClimaSeaIce.jl](https://github.com/CliMA/ClimaSeaIce.jl) for sea ice, SpeedyWeather or other atmospheric models, or use reanalysis products like JRA55 and ERA5 as prescribed forcing. + +## Language & Environment + +- **Julia 1.10+** | CPU and GPU (CUDA) +- **Key packages**: Oceananigans.jl, ClimaSeaIce.jl, SpeedyWeather.jl, + KernelAbstractions.jl, CUDA.jl, Enzyme.jl, Reactant.jl +- **Style**: ExplicitImports.jl for source code; `using NumericalEarth` for examples +- **Testing**: ParallelTestRunner.jl for distributed testing + +## Critical Rules + +### Kernel Functions (GPU compatibility) + +- Use `@kernel` / `@index` (KernelAbstractions.jl) +- Kernels must be **type-stable** and **allocation-free** +- Use `ifelse` — never short-circuiting `if`/`else` or ternary `?`/`:` in kernels +- No error messages, no Models inside kernels +- Mark functions called inside kernels with `@inline` +- **Never loop over grid points outside kernels** — use `launch!` +- **Use literal zeros**: `max(0, a)` not `max(zero(FT), a)`. Julia handles type promotion. + +### Type Stability & Memory + +- All structs must be concretely typed. **Never use `Any` as a type parameter or field type.** +- Use the **materialization pattern**: user-facing constructor creates a "skeleton" struct with + placeholder types (like `Nothing`), then `materialize_*` creates the fully-typed version. +- For mutable state within an immutable struct, use a `mutable struct` as the field type. +- Type annotations are for **dispatch**, not documentation +- Minimize allocation; favor inline computation + +### Imports + +- Source code: explicit imports (checked by tests). Never use `import` to extend functions; + always use `Module.function_name(...) = ...` or `function Module.function_name() ... end` +- Exports at the top of module files, before other code +- Import Oceananigans/NumericalEarth names first, then external packages +- Internal NumericalEarth imports use absolute paths, not relative +- Examples/docs: rely on `using Oceananigans` and `using NumericalEarth` + +### Docstrings + +- Use `$(TYPEDSIGNATURES)` from DocStringExtensions.jl (never write explicit signatures) +- **ALWAYS `jldoctest` blocks, NEVER plain `julia` blocks** — doctests are tested; plain blocks rot +- Include expected output after `# output`; prefer `show` methods over boolean comparisons +- **Citations**: Use inline `[Author (year)](@cite Key)` syntax woven into prose +- Use unicode for math (`θ`, `ρ`, `Π`), not LaTeX + +### Software Design + +- Minimize code duplication (allow only for trivial one-liners) +- When something would be better in Oceananigans, add a detailed TODO note +- Almost always extend functions in source code, not in examples +- Coding style: consult `docs/src/appendix/notation.md` for variable names +- Use math or English consistently in expressions; don't mix +- Keyword arguments: no-space for inline `f(x=1)`, single-space for multiline `f(a = 1, b = 2)` + +## Naming Conventions + +- **Files**: snake_case — `atmosphere_model.jl` +- **Types/Constructors**: PascalCase — `AtmosphereModel` +- **Functions**: snake_case — `compute_pressure!` +- **Kernels**: may prefix with underscore — `_kernel_function` +- **Variables**: English long name or unicode from `notation.md`. Add new variables to that table. +- **Avoid abbreviations**: `latitude` not `lat`, `temperature` not `temp` + +## Module Structure + +``` +src/ +├── NumericalEarth.jl # Main module, exports +├── Atmospheres/ # Interfaces for atmospheres (prescribed or diagnostic) +├── Bathymetry/ # Module for downloading and modifying bathymetry and topography +├── DataWrangling/ # Interfaces for atmospheres (prescribed or diagnostic) +├── Diagnostics/ # Various diagnostics from all model components +├── EarthSystemModels/ # Module that brings all Earth system model components together +├── InitialConditions/ # Module for initial conditions +├── Oceans/ # Interfaces for oceans (prescribed or diagnostic) +└── SeaIces/ # Interfaces for sea ices (prescribed or diagnostic) +``` + +## Common Pitfalls + +1. **Type instability** in kernels — ruins GPU performance +2. **Overconstraining types**: use annotations for dispatch, not documentation +3. **Missing imports**: tests will catch this — add explicit imports +4. **Plain `julia` blocks in docstrings**: always use `jldoctest` +5. **Subtle bugs from missing method imports**, especially in extensions +6. **Never extend `getproperty`** to fix undefined property bugs — fix the caller instead +7. **"Type is not callable"**: variable name shadows a function — rename or qualify +8. **Quick fixes that break correctness**: if a test fails after a change, revisit the original edit +9. **Scope creep in PRs**: keep changes focused on a single concern +10. **Modifying Project.toml dependencies**: never add, remove, or change `[deps]` or `[weakdeps]` + in the root `Project.toml` unless the task absolutely requires it. Dependency changes have + wide-reaching consequences — they affect CI, load time, and downstream compatibility. + Only touch `[compat]` bounds when explicitly asked. + +## Git Workflow & Whitespace + +Follow [ColPrac](https://github.com/SciML/ColPrac). Feature branches, descriptive commits, +update tests and docs with code changes, check CI before merging. + +**PRs fail CI with trailing whitespace or trailing blank lines.** Before committing: +remove trailing whitespace, remove trailing blank lines, ensure file ends with exactly one newline. + +## Agent Behavior + +- Prioritize type stability and GPU compatibility +- Follow established patterns in existing code +- Add tests for new functionality; update exports when adding public API +- Reference physics equations in comments when implementing dynamics +- When unsure: study working examples first (BOMEX, RICO, etc.), look at similar + Oceananigans implementations, review tests for usage patterns + +## Further Reading + +Detailed reference docs are in `.agents/` — read on demand: + +| Document | Content | +|----------|---------| +| `.agents/testing.md` | Running tests, writing tests, debugging, QA | +| `.agents/documentation.md` | Building docs, fast builds, Literate.jl examples, doctest details | +| `.agents/validation.md` | Reproducing paper results, common issues, TC genesis | +| `.agents/physics-debugging.md` | Thermodynamic variables, diagnose-before-fix, model architecture | + +### Auto-loading Rules + +Rules in `.claude/rules/` load automatically when you touch matching files: +- `kernel-rules.md` — GPU kernel requirements (src/) +- `docstring-rules.md` — docstring and jldoctest conventions (src/) +- `testing-rules.md` — test writing and running (test/) +- `docs-rules.md` — documentation building and style (docs/) +- `examples-rules.md` — Literate.jl example conventions (examples/) + +### Skills (slash commands) + +- `/run-tests` — run targeted tests, prioritized by what's likely to break +- `/build-docs` — build documentation locally +- `/add-feature` — checklist for adding new physics/features +- `/new-simulation` — set up, run, and visualize a new simulation +- `/babysit-ci` — monitor CI, auto-fix small issues, retrigger flaky runs diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..43c994c2d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md