This file provides guidance to AI coding agents working in this repository
(Claude Code and Cursor). AGENTS.md at the repo root and
.cursor/AGENTS.md are symlinks to this file.
solvcon is a hybrid C++/Python library for solving conservation laws using the space-time Conservation Element and Solution Element (CESE) method with unstructured meshes. The codebase emphasizes:
- High-performance numerical computing through C++ with Python bindings
- Multi-dimensional array operations and contiguous buffer management
- One-dimensional solvers demonstrating the CESE method
- Qt-based GUI (pilot) for spatial data visualization
- Integrated runtime profiler for performance analysis
This repository ships .claude/ and .cursor/ directories with permissions,
hooks, and skills tuned to this codebase. General behavioral rules live in
contrib/prompt/general-rule.md (not auto-imported). This section indexes
the tools.
cli.json-- project shell/file permissions (translated from.claude/settings.json;Shell(...)replaces Claude'sBash(...)).hooks.json--postToolUseonWrite|StrReplaceandafterFileEditonWrite|TabWrite, wired to the sharedcheck-source.shscript.hooks/-- symlink to.claude/hooks/.skills/-- symlink to.claude/skills/.AGENTS.md-- symlink toCLAUDE.mdat the repo root.statusline.sh-- symlink to.claude/statusline.sh. Point your~/.cursor/cli-config.jsonstatusLine.commandat$PROJECT/.cursor/statusline.sh(or.claude/statusline.sh).
cpp-style-review-- judgment-call C++ review (m_prefix, function-body placement,SimpleCollectorpreference, pybind11 binding split,const_cast). Scoped togit diff. Invoke after editing files incpp/orgtests/.python-style-review-- judgment-call Python review (naming, test intent, project conventions). Scoped togit diff. Invoke after editing files insolvcon/ortests/.
Skills inherit the caller's model rather than pinning their own. Deterministic style checks (ASCII, trailing whitespace, modeline, 79-char Python lines) are owned by hooks, not skills.
check-source.sh-- PostToolUse onWrite|Editof source files. Surfaces non-ASCII bytes, trailing whitespace, missing modeline, and Python>79chars; exits 2 withpath:line -- rule -- fix.check-doc-images.sh-- PreToolUse onBash. Blocks agit committhat stages a raster or pre-rendered image blob (.png,.jpg,.svg,.eps,.pdf, ...) underdoc/; exits 2 with the offending paths. Documentation schematics are authored as.texPSTricks rendered bypstake, so an image blob means a build artifact is being checked in instead of its source.
permissions.allowwhitelists the safemaketargets,cmake,pytest, lint/format tools, and read-only git/gh.make cleanandmake cmakecleandeliberately prompt.permissions.denyhard-blocks onlysudoandrm -rfof root/home. Destructive git operations (force-push,git reset --hard,git clean -fd) are discouraged but not blocked -- use them deliberately and only when asked.hookswires the scripts above (check-source.shonWrite|Edit,check-doc-images.shonBash).statusLineruns.claude/statusline.sh-- shows model, project, branch (with*if dirty), and context-window usage.
All workflows are driven through make from the repo root. The Makefile sets
PYTHONPATH=$(SOLVCON_ROOT) so the in-tree _solvcon extension is picked up
without installation, and works around macOS SIP stripping DYLD_LIBRARY_PATH.
Build
make-- build the_solvconPython extension (default target).make pilot-- build the Qt pilot GUI binary.make clean/make cmakeclean-- remove build artifacts.
Test
make pytest-- full Python test suite.make pytest PYTEST_OPTS="tests/test_buffer.py::SimpleArrayBasicTC::test_sort"-- run a single test or subset;PYTEST_OPTSis forwarded verbatim to pytest.make run_pilot_pytest-- Python tests that require the pilot GUI; acceptsPYTEST_OPTSthe same way.make gtest-- build and run the full C++ test suite../build/rel<pyvminor>/gtests/run_gtest --gtest_filter=Suite.Test-- run a single gtest aftermake gtesthas built the binary (<pyvminor>is the Python major+minor, e.g.314).make pyprof-- run profiling benchmarks; results land inprofiling/results/.
Lint (make lint runs all five)
make cformat-- check C++ formatting (read-only; usemake FORCE_CLANG_FORMAT=inplace cformatto fix).make cinclude-- check#includeordering and style.make flake8-- Python style and 79-char line limit.make checkascii-- reject non-ASCII bytes in source.make checktws-- reject trailing whitespace.
Format
Automatic formatting is still work in progress. Do not run make format or
make pyformat.
Any target whose tool (clang-format, flake8) is missing prints an install
hint and exits 1. make cformat also warns when the local clang-format major
version differs from the CI pin (CLANG_FORMAT_CI_VERSION in the Makefile).
Key build variables (set in setup.mk or as environment variables):
CMAKE_BUILD_TYPE:Release(default) orDebugBUILD_QT:ON(default) orOFF- build Qt GUI componentsBUILD_METAL:OFF(default) orON- build Metal GPU supportSOLVCON_PROFILE:OFF(default) orON- enable profilerUSE_CLANG_TIDY:OFF(default) orON- use clang-tidyHIDE_SYMBOL:ON(default) - hide Python wrapper symbolsDEBUG_SYMBOL:ON(default) - add debug information
Build paths ($(pyvminor) is the active Python major+minor, e.g. 314):
- Release builds (default):
build/rel<pyvminor>(e.g.,build/rel314) - Debug builds:
build/dbg<pyvminor>(e.g.,build/dbg314)
solvcon uses a dual-layer hybrid architecture:
-
C++ Core (
cpp/solvcon/): High-performance numerical code- Compiled to native libraries with pybind11 bindings
- Exposed to Python through the
_solvconextension module
-
Python Interface (
solvcon/): High-level API and utilities- Imports C++ components via
from .core import * - Provides Python-native functionality (plotting, utilities, etc.)
- Imports C++ components via
C++ core lives in cpp/solvcon/. Load-bearing pieces:
buffer/--ConcreteBuffer,SimpleArray,BufferExpander,small_vector.mesh/--StaticMesh(unstructured meshes with mixed element types).pilot/-- Qt GUI (entry point undercpp/binary/pilot/; needs Qt6 and PySide6).python/--module.cppis the main pybind11 module.
Other subdirectories cover what their names suggest: linalg/
(BLAS/LAPACK wrappers), inout/ (Gmsh, Plot3D), onedim/ (1D CESE
solvers), profiling/ (runtime profiler), simd/ (NEON/SSE/AVX),
transform/ (integral transform), universe/ (3D geometry), toggle/
(feature toggle), and per-component pymod/ subdirs for pybind11
wrappers. spacetime/ is an old, incorrect CESE implementation kept
for reference only -- do not extend it.
See cpp/solvcon/ for the current tree.
Python interface in solvcon/:
core.py: Main Python API wrapping the C++ extensiononedim/: One-dimensional solver utilitiespilot/: GUI application Python componentsplot/: Plotting utilitiesprofiling/: Profiling result analysistesting.py: Test utilitiestoggle.py: Feature toggle Python interface
Python tests are the default. Prefer writing tests in Python (tests/); reach
for C++ gtest only when the code cannot or should not be exercised from Python
-- for example, internals with no Python binding, or behavior that must be
verified at the C++ level.
- Python tests (
tests/): pytest-based, files namedtest_*.py. The preferred place for tests. - C++ tests (
gtests/): googletest-based, files namedtest_nopython_*.cpp. Use only when Python cannot or should not reach the code under test. - Profiling benchmarks (
profiling/): files namedprofile_*.py.
See "Build, Test, Lint, Format" above for the make invocations.
STYLE.md is the canonical source. At a glance:
- Line economy and breathing room: Keep a single thought compact (group
short declarations, do not spread simple logic across many lines), but let a
longer body breathe by separating its distinct steps with one blank line.
Do not pad short blocks, and do not compress a function into an unbroken
wall of statements. Always respect the linting line-width limits; never
sacrifice them to shorten the line count. See
STYLE.md"Line Economy and Breathing Room". - C++: 4-space indent,
m_prefix on member vars, angle-bracket includes, C++23, preferSimpleCollector/small_vectorover STL for fundamentals. - Python: PEP-8, 79-char hard limit, flake8.
- Comments: Default to none. Add one only for what the code cannot say
(the why, units, invariants, a non-obvious algorithm). Never restate the
code, narrate a step, or label obvious structure. When in doubt, leave it
out. See
STYLE.md"Comments" for examples. - All source: UTF-8, Unix LF, ASCII-only, no trailing whitespace, modeline at EOF.
- Documentation schematics: author figures as
.texPSTricks sources rendered bysolvcon/pstake(symlinked intodoc/ext/) at build time. Never check in image blobs (.png,.jpg,.svg,.eps,.pdf, ...) underdoc/; commit the.texsource instead, so the figure stays diffable and rebuilds from source.
How style is enforced in this repo:
.claude/hooks/check-source.showns the deterministic checks (ASCII bytes, trailing whitespace, modeline at EOF, Python>79-char lines)..claude/hooks/check-doc-images.shblocks committing image blobs underdoc/, keeping schematics in.tex/PSTricks form (rendered bypstake).- The
cpp-style-reviewandpython-style-reviewskills in.claude/skills/own the judgment-call rules (m_prefix in context, function-body placement, container choice, pybind11 binding split, test intent). They are scoped togit diff.
For the full rule set with examples, see STYLE.md.
When opening a pull request, reference the related issue (e.g., "Related to #725") instead of using closing keywords like "close #725", "closes #725", or "fixes #725". We do not let PR and commit log comments to mandate the management.
This applies to every passage you write for humans: code comments, commit messages, PR and issue descriptions and comments, and documentation.
- Minimize em-dashes (the "--" rendered as a long dash, or the Unicode
U+2014character). They are hard to read. Prefer a comma, a colon, parentheses, or two separate sentences. Reserve a dash only when no other punctuation reads as clearly. - Source files are ASCII-only (see "Code Style"), so never emit the Unicode em-dash, en-dash, or "smart quotes" in them. The same restraint is expected in GitHub prose even though GitHub accepts Unicode.
- Write plainly. Short sentences beat long ones strung together with dashes.
- CMake is the primary build system (minimum version 3.27)
- Makefile wraps CMake for convenience
- Python extension built via setuptools with custom CMake integration
- Build output:
_solvcon.cpython-<version>-<platform>.soinsolvcon/
Core dependencies:
- Python 3 with development headers
- pybind11 >= 2.12.0 (for NumPy 2.0 support)
- NumPy
- CMake >= 3.27
- C++23 compiler (gcc, clang, or MSVC)
Optional dependencies:
- Qt6 and PySide6 (for GUI)
- clang-tidy (for linting)
- googletest (auto-fetched by CMake)
- Metal (for macOS GPU support)
Install scripts available in contrib/dependency/
IMPORTANT: Using Python virtual environments (venv, conda) is strongly discouraged for solvcon development. The project is designed to work with system Python. Virtual environment bugs are not actively resolved.
Use https://github.com/solvcon/devenv to build dependency from source and install in user space. Do not install dependency system-wide. Installation of any dependency requires user review and consent.
macOS: System Integrity Protection (SIP) may interfere with
DYLD_LIBRARY_PATH. The Makefile sets PYTHONPATH as a workaround.
solvcon includes an integrated runtime profiler:
- Enable with
SOLVCON_PROFILE=ONduring build - Use
toggle.pyAPI to enable/disable profiling regions - Run profiling scripts with
make pyprof - Results written to
profiling/results/
The pilot application (cpp/binary/pilot/) is a standalone Qt6-based viewer:
- Requires
BUILD_QT=ON(default) - Uses PySide6 for Python-Qt integration
- Resource files in
resources/pilot/ - Can be disabled with
BUILD_QT=OFFfor headless builds
- Create a directory under
cpp/solvcon/. - Add header files with proper include guards.
- Update
cpp/solvcon/CMakeLists.txtto include new sources. - Add pybind11 bindings if Python access is needed.
- Write tests. Prefer Python tests in
tests/; add agtests/test only when the behavior cannot or should not be exercised from Python.
- Add a module to
solvcon/. - Update
solvcon/__init__.pyif needed. - Write tests in
tests/. - Update
setup.pypackages list if adding a new package.
- Use
ConcreteBufferfor raw memory. - Use
SimpleArrayfor typed multi-dimensional arrays. - Buffers support both ownership and non-owning views.
- Python and C++ share the same buffer memory (zero-copy).