morph is a header-only C++23 library. You need a C++23 compiler, CMake with
Ninja, and the dependencies declared in vcpkg.json (Glaze, Catch2; Qt 6 only
when building the optional Qt integration, -DMORPH_BUILD_QT=ON). CMake
presets are provided — cmake --list-presets shows the configured matrix; the
README documents the full set of build options
(MORPH_BUILD_TESTS, MORPH_BUILD_EXAMPLES, MORPH_BUILD_QT,
MORPH_BUILD_FORMS_QML, …).
A plain configure/build/test loop:
cmake -S . -B build -G Ninja
cmake --build build
ctest --test-dir build --output-on-failuredocs/spec/ is the authoritative design reference — one file per public
type or subsystem. The rules, from CLAUDE.md:
- Before changing any public type or subsystem, read its spec. The spec carries the invariants and reasoning the code alone does not.
- If a change invalidates any part of a spec, update the spec in the same
change — never the other way around. Where
docs/ARCHITECTURE.md(the cross-cutting map) and a spec disagree, the spec wins. - Planned work lives in
docs/planned/, one spec per feature, each with aStatus: planned — not yet implementedbanner;docs/todo.mdis the prioritised index. When you implement one: build against the spec, then flip its banner and rewrite it to present tense, and updateARCHITECTURE.md. - Feature docs (
docs/superpowers/) are compressed reference docs — one file per feature, under 500 lines, present tense only, no changelogs or migration notes (git history covers that).
-
Tests: behavior changes come with Catch2 tests under
tests/. -
Doxygen is strict: the Docs CI job runs with
WARN_AS_ERROR = FAIL_ON_WARNINGS— every public symbol needs complete@param/@tparam/@returndocs. Reproduce locally withcmake -S . -B build -G Ninja -DMORPH_BUILD_DOCUMENTATION=ON -DMORPH_BUILD_TESTS=OFF -DMORPH_BUILD_EXAMPLES=OFFandcmake --build build --target doc. -
Formatting/linting:
.clang-formatand.clang-tidygovern C++; markdown follows.markdownlint.yaml(119-column limit; code blocks and tables exempt).pre-commit run --all-filesruns the configured hooks. -
Keep mechanical facts honest:
docs/spec/pinned_facts.tomlpins the mechanical facts that recur across specs — enum cardinalities, key constants (kMaxEnvelopeBytes,kMaxDecimalPlaces,kClockSkewMs), canonical error/reply strings, and glaze parsing behavior (error_on_unknown_keys = false, duplicate-key last-wins). Two CI checks enforce it:tests/test_pinned_facts.cppasserts the real code symbols against a headercmake/pinned_facts.cmakegenerates from the manifest at configure time — astatic_assert/exhaustive-switchcompile-time gate where the type system allows it, a Catch2 runtimeREQUIREwhere it does not (an exception'swhat(), aRemoteServerreply string, a glaze option that has no reachable symbol). It runs as part of the normalmorph_teststarget, so it is checked under every compiler in the CI matrix.scripts/check_spec_citations.sh(the "Drift guard" workflow) asserts every pinned value is still cited in the spec file that documents it, and that no banned, superseded terminology (e.g. the pipe-delimited-era "N-part protocol" wording) has crept back intodocs/spec/,docs/ARCHITECTURE.md, orinclude/.
If you change a pinned constant, enum cardinality, or canonical error string, update the code,
docs/spec/pinned_facts.toml, and the spec prose that cites it together in the same commit.
Suspected vulnerabilities go through private reporting — see SECURITY.md, not the public issue tracker.
morph is Apache-2.0 (see LICENSE); contributions are accepted under the same license.