| # AGENTS.md | |
| Guidance for AI coding agents working in Eigen. Human contributors should start with | |
| [`README.md`](README.md) and the project documentation it links to. Per-tool files such as `CLAUDE.md` should import | |
| this file and contain only tool-specific additions. | |
| ## Scope and precedence | |
| Follow the user's task, then the nearest applicable `AGENTS.md`, then repository documentation and established local | |
| patterns. The checked-out source, tests, CMake files, and CI configuration are the authority on how things currently | |
| work. If this guide disagrees with the tree, follow the tree, report the discrepancy, and update the guidance when | |
| that is in scope. | |
| Read this file for every task. Then read the guides in every row below that matches the work. Do not load unrelated | |
| guides by default. | |
| | Work area | Additional guidance | | |
| |---|---| | |
| | Any new or rewritten code | [`.agents/conventions.md`](.agents/conventions.md) | | |
| | Tests and CMake test targets | [`.agents/testing.md`](.agents/testing.md) | | |
| | Numerical kernels, decompositions, solvers, accuracy | [`.agents/numerics.md`](.agents/numerics.md) | | |
| | Sparse matrices, sparse solvers, external sparse backends | [`.agents/sparse.md`](.agents/sparse.md) | | |
| | Performance changes and benchmarks | [`.agents/benchmarking.md`](.agents/benchmarking.md) | | |
| | Comparing against, benchmarking against, or integrating external libraries | [`.agents/provenance.md`](.agents/provenance.md) | | |
| | Packet math, CUDA, HIP, SYCL, `contrib/Eigen/GPU` | [`.agents/simd-gpu.md`](.agents/simd-gpu.md) | | |
| | Tensor, ThreadPool, and multithreading | [`.agents/tensor-threadpool.md`](.agents/tensor-threadpool.md) | | |
| | Formatting, lint, and GitLab CI | [`.agents/ci.md`](.agents/ci.md) | | |
| | Doxygen blocks, `doc/` pages, snippets, and examples | [`.agents/docs.md`](.agents/docs.md) | | |
| | Changes under `ci/`, `.gitlab-ci.yml`, or the test-selection and cache scripts | [`.agents/ci-internals.md`](.agents/ci-internals.md) | | |
| | Writing or updating a merge request description | [`.agents/merge-requests.md`](.agents/merge-requests.md) | | |
| | Answering merge request review comments | [`.agents/review-response.md`](.agents/review-response.md) | | |
| | Editing `AGENTS.md` or a guide under `.agents/` | [`.agents/writing-guidance.md`](.agents/writing-guidance.md) | | |
| | Expression templates or evaluator internals | [`doc/TopicLazyEvaluation.dox`](doc/TopicLazyEvaluation.dox), [`doc/NewExpressionType.dox`](doc/NewExpressionType.dox), and [`doc/ClassHierarchy.dox`](doc/ClassHierarchy.dox) | | |
| The wording of a rule sets its strength: | |
| - *Must*, *must not*, *never*, and a plain imperative state a requirement. Depart from one only when the user tells you | |
| to, and report any requirement you could not meet. | |
| - *Prefer*, *avoid*, *should*, and *usually* state a default. Depart from one when the task gives a concrete reason, and | |
| give that reason in your report. | |
| - *May* grants permission. For possibility, the guides write *can* or *might*. | |
| ## Non-negotiable rules | |
| 1. **Preserve existing work.** Start with `git status --short`. Never discard, overwrite, reformat, or stage unrelated | |
| user changes. Do not use destructive Git commands unless the user explicitly requests that operation. Stage named | |
| paths, never `git add .` or `git add -A`. | |
| 2. **Keep provenance clean.** Code must be original or derived from source material whose license is compatible with | |
| Eigen's MPL-2.0 distribution. Do not copy, paraphrase, or translate code from proprietary, NDA-covered, internal, or | |
| incompatibly licensed sources. Published papers, standards, textbooks, and algorithm descriptions may inform an | |
| independent implementation. Cite each one inline where it materially informs the implementation. A citation does | |
| not make copied code permissible. The rule covers information as well as code. Treat proprietary software as a black | |
| box: use it only through its documented interface and measure it as shipped. Never disassemble, dump, debug into, or | |
| alter it; see [`.agents/provenance.md`](.agents/provenance.md). Never invent an attribution for AI-generated code. A | |
| `Co-Authored-By` trailer for the model that actually produced the change is accurate attribution, and is permitted. | |
| 3. **Respect the header-only and C++14 contracts.** Supported headers must compile as C++14, unless a backend behind a | |
| preprocessor guard has a documented newer requirement. In user code, examples, and public-behavior tests, include | |
| umbrella headers such as `Eigen/Core` or `Eigen/SVD`, not files below `Eigen/src/` or `contrib/Eigen/src/`. Where | |
| nearby tests establish the pattern, a focused test of a private utility may include the utility's header directly. | |
| Those paths remain private even where the header has no `InternalHeaderCheck.h` guard. Definitions in public headers | |
| must have linkage that is valid in a header and must not cause one-definition-rule (ODR) violations. | |
| 4. **Protect compatibility.** Treat supported public names, signatures, header paths, semantics, and ABI-affecting | |
| configuration as compatibility surfaces. Prefer additive changes and deprecation over removal. When you move a | |
| private implementation header, update the public umbrella header and delete the old private file rather than adding a | |
| forwarding shim at the old path. ABI-affecting Eigen macros must be consistent across translation units. | |
| 5. **Preserve Eigen annotations and style.** Do not drop `EIGEN_DEVICE_FUNC` from coefficient-level or device-callable | |
| functions. Do not replace `EIGEN_STRONG_INLINE` with `inline`, reorder includes, normalize Eigen macro layout, or | |
| apply broad `modernize-*` or `cppcoreguidelines-*` rewrites. The repository's conventions and `.clang-format` take | |
| precedence over generic C++ advice. This rule covers code your task does not otherwise change. Write new | |
| declarations in the current form that [`.agents/conventions.md`](.agents/conventions.md) describes, not in the | |
| superseded form around them. | |
| 6. **Enable a fast path only when the property it needs holds.** For a new specialization, capability flag, or enable | |
| condition, state the exact precondition it depends on and check for that. Do not check for an adjacent capability, | |
| for the existence of an overload, or for a property the built-in types merely happen to share. Give a new opt-in | |
| trait the conservative default. Extension points that users can specialize must stay correct when users leave them | |
| unannotated. | |
| 7. **Ship verification with behavior.** Add focused tests with new functionality. With a bug fix, add a regression test | |
| that fails without the fix when practical. With a performance-sensitive change, add an appropriate benchmark. Scale | |
| broader coverage to the affected scalar types, storage orders, backends, and public contracts. Confirm the new test | |
| fails at the parent commit when practical; otherwise show that the test runs the changed code by construction. See | |
| [`.agents/testing.md`](.agents/testing.md). | |
| 8. **Treat external writes as deliberate actions.** Push, open or update a merge request, comment on an issue, or write | |
| to any other external system only when the user has asked for that action. Otherwise, stop after the local commit and | |
| ask. Recommend the `affected-tests` label with the relevant platform labels, or with `all-platforms` for broader | |
| coverage; see [`.agents/ci.md`](.agents/ci.md). Do not add `all-tests` without the user's explicit permission for | |
| that label. | |
| ## Standard workflow | |
| 1. Inspect `git status --short`, the current branch, and the diff. Separate pre-existing work from the requested change. | |
| 2. As applicable, read the public header, implementation, nearby tests, registration in `CMakeLists.txt`, and relevant | |
| task guides before deciding on an implementation. Search with `rg` or `rg --files` (add `--hidden` to search | |
| `.agents/`). Before writing a helper, check `numext`, `NumTraits`, `MathFunctions.h`, `Meta.h`, `XprHelper.h`, and | |
| the `test/*_helpers.h` headers for an existing one. If one exists but lacks the hardening you need, fix it there | |
| rather than adding a local copy. | |
| 3. Keep the patch within the owning module and established patterns. Avoid opportunistic refactors and churn in | |
| generated files or metadata. | |
| 4. Add or update applicable tests and benchmarks in the same patch. Test public behavior through its umbrella header, so | |
| the test catches anything the umbrella fails to export. Follow nearby patterns for focused tests of private | |
| internals. | |
| 5. Inspect the diffs of the files you are about to format, so that you do not format unrelated changes. Then format the | |
| task's changed lines with `git clang-format --binary clang-format-17 --force <base-sha> -- <files>`; `--force` lets | |
| the command format files that have unstaged edits. Format task-created files with `clang-format-17 -i <files>`, | |
| because untracked files are absent from the diff. Formatting a whole existing file, or running `scripts/format.sh`, | |
| also rewrites older lines that are not clang-format-17 clean. Use them only when you intend that churn. See | |
| [`.agents/ci.md`](.agents/ci.md) for the matching check. | |
| 6. Build and run the narrowest relevant test first, then widen validation according to the change's risk. Use separate | |
| build directories for materially different CMake configurations. | |
| 7. Review `git diff --check`, `git diff`, and `git status --short`. Report the exact validation run and any unavailable | |
| compiler, ISA, GPU, dependency, or downstream coverage. | |
| 8. When review comments arrive, follow [`.agents/review-response.md`](.agents/review-response.md). | |
| ## Repository essentials | |
| Eigen is a header-only expression-template library. Consumers include module headers under `Eigen/` or | |
| `contrib/Eigen/`. The top-level CMake project builds tests, documentation, demos, and BLAS/LAPACK shims rather than | |
| a core Eigen library; benchmarks use separate CMake projects. `Eigen/Dense` aggregates the dense modules, while | |
| `Eigen/Eigen` includes `Dense` and `Sparse`. External backend support modules and `Eigen/ThreadPool` remain separate | |
| includes. The upstream project is on GitLab; its GitHub repository is a read-only mirror. | |
| The supported implementation is under `Eigen/src/`; tests are under `test/`. Modules with looser API-stability | |
| guarantees are under `contrib/Eigen/`, with tests under `contrib/test/`. Legacy `unsupported/Eigen/...` include paths | |
| remain valid: one-line forwarding shims under `unsupported/Eigen/` point at the `contrib/` headers and are installed | |
| alongside them. "Contrib" does not imply low impact: Tensor is a foundational TensorFlow dependency. A module's public | |
| umbrella header is the source of truth for which internals the module exports. | |
| The `lapack/*.f` files are vendored copies of the netlib LAPACK reference sources and are read-only here. Do not edit | |
| them ad hoc. Flag a merge request that changes one. The exception is an explicit refresh from a named netlib release; | |
| check that diff against the release. `.git-blame-ignore-revs` lists the commits that ran | |
| clang-format or added SPDX tags across the whole tree. To see the history beneath them, pass that file to `git blame` | |
| with `--ignore-revs-file`. | |
| Every new source file needs accurate REUSE metadata; [`.agents/conventions.md`](.agents/conventions.md) records the | |
| required header form and the `REUSE.toml` rules for files that cannot carry an inline tag. | |
| ## Essential Eigen hazards | |
| ### Expressions, lifetimes, and aliasing | |
| Eigen expressions are lazy and frequently retain references. Assignment, construction, coefficient access, reductions, | |
| and `.eval()` can all consume an expression. | |
| - `auto x = A + B;` stores a lazy expression whose references can dangle. When ownership is required, materialize it | |
| with `(A + B).eval()` or use an appropriate plain-object type such as `Matrix` or `Array`. | |
| - `.noalias()` is a promise, not a runtime check. Use it only when the destination cannot appear in the right-hand side. | |
| Product evaluation makes `mat = mat * mat` safe; `mat.noalias() = mat * mat` is wrong. | |
| - Prefer Eigen expressions when they express the operation clearly and avoid repeated evaluation. Keep a scalar loop | |
| when it represents control flow better, avoids an unnecessary temporary, or has measured performance benefits. | |
| - Prefer block and view expressions when a uniform operation or existing Eigen method applies to a submatrix; for | |
| example, scale a 2-by-2 block or call its `determinant()` instead of spelling out its coefficients. When a block's | |
| size is known at compile time, preserve that compile-time size with a fixed-size accessor such as `block<Rows, | |
| Cols>(i, j)`. In dependent template code, write `m.template block<Rows, Cols>(i, j)`. Use runtime sizes only when they | |
| are genuinely dynamic. Use individual coefficient access when entries require different operations. Blocks remain | |
| lazy, non-owning views, so the lifetime and overlap rules above still apply. | |
| - The two arms of `?:` must have a common C++ type; distinct Eigen expression types often do not. Use `if`/`else` when | |
| necessary. | |
| - Declare dynamically sized matrix and vector workspaces outside the loop that fills them. A plain object declared | |
| inside the loop body allocates on every iteration. So does every subexpression in the loop body that materializes a | |
| temporary. | |
| ### Scalar, index, and storage genericity | |
| Use `Eigen::Index` for dimensions and counts, but remember that its underlying type is configurable. Use `NumTraits` for | |
| scalar properties, and Eigen's `numext` helpers when the code must support custom scalars or device code. Do not: | |
| - store sizes or loop counts in `Scalar`; | |
| - hard-code `float`/`double` without an API reason; | |
| - narrow a value to the `int` a vendor API takes without checking the range. | |
| Test the real, complex, integer, and narrow or custom scalar types that the operation's documented domain covers. | |
| Commutativity, exactness, the tie behavior of `min`/`max`, and other algebraic properties of the built-in types need | |
| not hold for every `Scalar`. Establish such a property for each scalar category, and leave custom scalars on the | |
| conservative path. | |
| Propagate storage-order and expression flags deliberately. `RowMajorBit`, fixed versus dynamic dimensions, alignment, | |
| and vectorization eligibility affect evaluators and fast paths. Eigen alignment depends on configuration and | |
| architecture; do not hard-code an assumed byte value. When configuration-sensitive behavior changes semantics or ABI, | |
| cover it in tests. | |
| ### Public APIs and diagnostics | |
| For generic APIs, accept the least restrictive established Eigen base (`EigenBase`, `DenseBase`, `MatrixBase`, | |
| `ArrayBase`, or a suitable `Ref`) that preserves the intended semantics. When the function writes to an expression | |
| argument, follow the established patterns nearby. Do not cast away constness from genuinely const storage. When you add | |
| a non-template definition or object to a public header and an ODR regression is plausible, add a link test that | |
| includes the header from multiple translation units. | |
| Pass fixed-size vectorizable Eigen objects by reference rather than by value. C++17 passes over-aligned objects by value | |
| safely, but the supported C++14 configurations cannot rely on that. See | |
| [`doc/PassingByValue.dox`](doc/PassingByValue.dox). | |
| Use `eigen_assert` for runtime preconditions that are part of Eigen's public debug behavior, and `eigen_internal_assert` | |
| for internal invariants, which are checked only when `EIGEN_INTERNAL_DEBUGGING` is defined. Use the local compile-time | |
| assertion style that gives the clearest diagnostic. | |
| Comments should explain non-obvious mathematics, invariants, compatibility constraints, or provenance rather than | |
| narrating the code. Keep comments concise and proportional to the code's complexity. Avoid tutorial-style prose, | |
| section-by-section narration, and comments that restate identifiers or control flow. Longer comments are justified only | |
| when their rationale cannot be expressed clearly in code. Reviewers here read mathematics and code faster than English: | |
| where a formula, a recurrence, an error bound, or two lines of pseudo-code state the point more precisely than a | |
| paragraph, write that instead. The same preference applies to merge request descriptions and review comments; | |
| [`.agents/merge-requests.md`](.agents/merge-requests.md) records the KaTeX syntax GitLab renders. | |
| ## Quick build and test | |
| By default, tests are not part of the `all` target, although that target can build configured auxiliary libraries. A | |
| typical focused workflow is: | |
| ```bash | |
| cmake -G Ninja -S . -B build | |
| cmake --build build --target <test-name> | |
| ctest --test-dir build -R '^<test-name>$' --output-on-failure --no-tests=error | |
| ``` | |
| For one part of a split test, such as `foo_3`, build that exact target and match it exactly with CTest. Keep | |
| `--no-tests=error`, because without it a filter that matches nothing exits 0. The generated `buildtests.sh` and | |
| `check.sh` wrappers accept regexes over source or test names and are useful for building all matching parts. Use | |
| `buildtests`, `BuildOfficial`, `BuildContrib`, `buildsmoketests`, or `check` only when the requested validation warrants | |
| that scope. See [`.agents/testing.md`](.agents/testing.md) for the current test framework, split rules, configuration | |
| variants, and failure-test workflow. | |
| ## Completion checklist | |
| Before declaring the task complete: | |
| - The diff contains only intentional changes and preserves pre-existing work. | |
| - New public implementation is reachable through the intended umbrella header. | |
| - New files have correct REUSE metadata and no generated or local-tool files are staged. | |
| - Changed source lines and task-created source files pass the clang-format-17 checks in `.agents/ci.md`; | |
| `git diff --check` is clean. | |
| - Documentation of the changed behavior is updated with it: the Doxygen block above a changed declaration, the module | |
| `README`, and nearby comments that name a value or precondition the change moved. | |
| - Focused regression tests pass, with broader tests or benchmarks run when the risk warrants them. | |
| - Numerical, aliasing, scalar, storage-order, device, threading, and ABI implications have been considered where | |
| relevant. | |
| - The final report names validation performed, residual risk, and anything that could not be tested locally. | |
| Prefer commit subjects of the form `Category: Short description`, for example | |
| `Core: Fix alias handling in product assignment`. |