Guidance for AI coding agents working in Eigen. Human contributors should start with 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.
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 authoritative for current mechanics. 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 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 |
| Tests and CMake test targets | .agents/testing.md |
| Numerical kernels, decompositions, solvers, accuracy | .agents/numerics.md |
| Sparse matrices, sparse solvers, external sparse backends | .agents/sparse.md |
| Performance changes and benchmarks | .agents/benchmarking.md |
Packet math, CUDA, HIP, SYCL, unsupported/Eigen/GPU | .agents/simd-gpu.md |
| Tensor, ThreadPool, and multithreading | .agents/tensor-threadpool.md |
| Formatting, lint, and GitLab CI | .agents/ci.md |
| Expression templates or evaluator internals | doc/TopicLazyEvaluation.dox, doc/NewExpressionType.dox, and doc/ClassHierarchy.dox |
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.Co-Authored-By trailer naming the model that actually produced the change is accurate attribution, not an invented one, and is permitted.Eigen/Core or Eigen/SVD, not files below Eigen/src/ or unsupported/Eigen/src/. Focused tests of private utilities may follow an established direct-include pattern, but those paths remain private even where a header is not mechanically guarded. Definitions in public headers must have valid header linkage and avoid ODR violations.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 protects code you are not otherwise changing; it does not license writing new code in a superseded form. Write new declarations in the form .agents/conventions.md records..agents/testing.md.git status --short, the current branch, and the diff. Separate pre-existing work from the requested change.CMakeLists.txt, and relevant task guides before deciding on an implementation. Search with rg or rg --files. Before writing a helper, check numext, NumTraits, MathFunctions.h, Meta.h, XprHelper.h, and the test/*_helpers.h headers for an existing one; if it exists but lacks needed hardening, fix it there rather than adding a local copy.clang-format-17 -i <files>. scripts/format.sh rewrites matching files across the tree; use it only when the worktree is clean and a whole-tree pass is intentional.git diff --check, git diff, and git status --short. Report the exact validation run and any unavailable compiler, ISA, GPU, dependency, or downstream coverage.A posted code suggestion is a sketch that has not been compiled; verify it like your own work before adopting it — including the C++14 baseline, Matrix/Array and expression-type mismatches, and numerically deliberate groupings. Address every thread: apply the suggestion or explain the deviation, naming the commit that resolved it. Keep the response within the comment's scope; a defect it exposes in shared code belongs in its own commit or merge request. After each round, re-verify that the merge request description and commit messages still describe the current head.
Eigen is a header-only expression-template library. Consumers include module headers under Eigen/ or unsupported/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 unsupported/Eigen/, with tests under unsupported/test/. “Unsupported” does not imply low impact: Tensor is a foundational TensorFlow dependency. Public umbrella headers are the source of truth for a module's exported internals.
Every new source file needs accurate REUSE metadata; .agents/conventions.md records the required header form and the REUSE.toml rules for files that cannot carry an inline tag.
Eigen expressions are lazy and frequently retain references. Consumption can occur through assignment, construction, coefficient access, reductions, or .eval().
auto x = A + B; stores a lazy expression whose references may dangle. Materialize with (A + B).eval() or use an appropriate plain-object type when ownership is required..noalias() is a promise, not a runtime check. Use it only when the destination cannot appear in the right-hand side. mat = mat * mat is protected by product evaluation; mat.noalias() = mat * mat is wrong.determinant() instead of spelling out its coefficients. Preserve known extents with fixed-size accessors such as block<Rows, Cols>(i, j); in dependent template code, write m.template block<Rows, Cols>(i, j). Use runtime extents only when they are genuinely dynamic, and use individual coefficient access when entries require different operations. Blocks remain lazy, non-owning views, so the lifetime and overlap rules above still apply.?: must have a common C++ type; distinct Eigen expression types often do not. Use if/else when necessary.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 custom-scalar or device support matters. Do not store sizes or loop counts in Scalar, hard-code float/double without an API reason, or narrow to a vendor API’s int without checking the range. Test real, complex, integer, and narrow/custom scalar types according to the operation's documented domain. An algebraic property that holds for the built-in types — commutativity, exactness, tie behavior of min/max — is not a property of every Scalar; establish it per 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 encode a presumed byte value. Include configuration-sensitive behavior in tests when it changes semantics or ABI.
For generic APIs, accept the least restrictive established Eigen base (EigenBase, DenseBase, MatrixBase, ArrayBase, or a suitable Ref) that preserves the intended semantics. Follow nearby established patterns for writable expression arguments; do not cast away constness from genuinely const storage. Public-header additions with non-template definitions or objects deserve a multiple-translation-unit link test when an ODR regression is plausible.
The supported C++14 configurations cannot rely on C++17 over-aligned value passing. Pass fixed-size vectorizable Eigen objects by reference rather than by value; see doc/PassingByValue.dox.
Use eigen_assert for runtime preconditions that belong to Eigen‘s public debug behavior and eigen_internal_assert for internal invariants gated by EIGEN_INTERNAL_DEBUGGING. 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 that rationale cannot be expressed clearly in code.
By default, tests are not part of the all target, although that target may build configured auxiliary libraries. A typical focused workflow is:
cmake -G Ninja -S . -B build cmake --build build --target <test-name> ctest --test-dir build -R '^<test-name>$' --output-on-failure
For a split test such as foo_3, build that exact target and match it exactly with CTest. The generated buildtests.sh and check.sh wrappers accept source/test-name regexes and are useful for building all matching parts. Use buildtests, BuildOfficial, BuildUnsupported, buildsmoketests, or check only when the requested validation warrants that scope. See .agents/testing.md for the current test framework, split rules, configuration variants, and failure-test workflow.
Before declaring the task complete:
clang-format-17; git diff --check is clean.README, and nearby comments naming a value or precondition the change moved — is updated with it.Commit subjects normally use Category: Short description, for example Core: Fix alias handling in product assignment.