This repository is a generic CMake-first C++ project frame optimized for agentic development.
Baseline shape:
- CMake is the only supported build system
- C++23 is the baseline language standard
- Out-of-tree builds are the default workflow
- Repo-owned code should stay portable, local-first, and easy to validate
- One small library target plus one CLI target form the default example shape
- Deterministic
CTest,clang-tidy,clang-format,cppcheck, Doxygen, release-hygiene, Valgrind, and coverage lanes are part of the maintained contract - Qt/Clazy provide the example UI stack, not the baseline assumption
- Public docs are generated from repo-owned headers and
docs/mainpage.md - Feature plans live under
feature_records/as tracked Markdown files using lifecycle subdirectories such asactive/,planned/,done/, andsuperseded/(seefeature_records/TEMPLATE.mdfor the expected format) config/change-contract-policy.shis the repo-local source of truth for change- contract paths, required sections, evidence lanes, and default validation profiles- Feature plans act as change contracts: they must declare maintained/new contract points, lifecycle state, uncertainty/cost bands, implementer and verifier ownership, an evidence matrix, implementation notes, verification command/result notes, and any waivers explicitly
- CMake presets provide named configurations for common workflows
Repository principles:
- Keep generated artifacts out of the repository
- Keep publication-facing files free of machine-specific paths and broken local links
- Prefer small explicit abstractions, clear ownership, and incremental changes
- Keep CI, docs, tests, and release scripts aligned with shipped behavior
- Treat vendored third-party code as subtree/vendor content, not normal project code
src/: repo-owned library and CLI codetests/: deterministic example tests, test registration, andframe_test.hmicro-frameworkdocs/: Doxygen config and API-focused main pagescripts/: hygiene, release, and diagnostics helperscontrib/: optional service/desktop integration examplescmake/: reusable analyzer helper scripts.agents/skills/: project-local agent overlays and merged skillsconfig/change-contract-policy.sh: repo-local change-contract policy shared by the checker and overlay skill.github/workflows/: generic CI and release workflow templatesbenchmarks/: optional chrono-based micro-benchmarks andframe_bench.hharnessfeature_records/: root template/README plus lifecycle-grouped feature records
Read README.md first before changing build, setup, or release behavior.
Prefer CMake presets for common workflows:
cmake --preset dev
cmake --build build/dev -j"$(nproc)"Available presets: dev (debug + sanitizers), release (optimized + LTO),
ci (matches GitHub Actions), coverage (gcov instrumentation).
Manual out-of-tree build (when presets are unavailable):
BUILD_DIR="$(mktemp -d /tmp/cpp-frame-build-XXXXXX)"
cmake -S . -B "$BUILD_DIR" -G Ninja
cmake --build "$BUILD_DIR" -j"$(nproc)"If ninja-build is unavailable, omit -G Ninja.
Optional sanitizer lane (included in the dev preset):
cmake -S . -B "$BUILD_DIR" -G Ninja \
-DFRAME_ENABLE_ASAN=ON \
-DFRAME_ENABLE_UBSAN=ONLightweight default validation:
"$BUILD_DIR/frame_cli" --helpUse the smallest validation set that proves the change, then extend as needed:
ctest --test-dir "$BUILD_DIR" --output-on-failurecmake --build "$BUILD_DIR" --target clang-tidycmake --build "$BUILD_DIR" --target clazywhen the project uses the example Qt-based UI stack and the tool is availablecmake --build "$BUILD_DIR" --target format-checkcmake --build "$BUILD_DIR" --target lint(includes clang-tidy and cppcheck when available)cmake --build "$BUILD_DIR" --target docsbash scripts/run-valgrind.sh "$BUILD_DIR"bash scripts/check-release-hygiene.shbash scripts/check-change-contracts.sh
If install layout or shipped assets change, validate a temporary install prefix:
INSTALL_DIR="$(mktemp -d /tmp/cpp-frame-install-XXXXXX)"
cmake --install "$BUILD_DIR" --prefix "$INSTALL_DIR"Run cmake --build "$BUILD_DIR" --target format before committing to keep
source files consistently formatted. CI enforces format-check and will reject
unformatted code. The .clang-format config at the repo root defines the
canonical style.
Build with the coverage preset and run the coverage target:
cmake --preset coverage
cmake --build build/coverage
cmake --build build/coverage --target coverageThis runs tests and collects coverage via gcovr. HTML output lands in
build/coverage/coverage/. New code should maintain or improve line coverage.
Build with -DFRAME_ENABLE_BENCHMARKS=ON and run manually:
cmake --build "$BUILD_DIR" --target example_bench
"$BUILD_DIR/benchmarks/example_bench"Add benchmarks for hot paths, algorithms, and performance-sensitive code.
Use FRAME_BENCHMARK(name, iterations) from benchmarks/frame_bench.h.
When adapting this frame for a new project, use the init script:
./scripts/init-project.sh --name "Your Project Name" # dry-run
./scripts/init-project.sh --name "Your Project Name" --applyThis renames all placeholder targets, namespaces, prefixes, and filenames.
- Keep repo-owned tests deterministic and headless under
CTest - Use the
frame_test.hmicro-framework:FRAME_TEST(name)for registration,FRAME_EXPECT_EQ,FRAME_EXPECT_TRUE,FRAME_EXPECT_FALSE,FRAME_EXPECT_THROWSfor assertions,FRAME_RUN_TESTS()in main - Keep
WHAT/HOW/WHYcommentary near the start of real test bodies; the repo scripts enforce that contract - Prefer pure helper seams and injected fakes over environment-heavy tests
- Prefer parser, config, algorithm, and boundary-helper coverage before device, network, UI, or platform integration coverage
- If Qt GUI or Widgets tests are added, make
CTestregistration itself setQT_QPA_PLATFORM=offscreen
- Keep changes targeted; do not reformat unrelated code
- Prefer small direct classes and explicit ownership/lifetime over broad abstraction layers
- Favor
const,override,explicit,[[nodiscard]], narrow enums, RAII, rule-of-zero types, and clear invariants - Treat raw pointers and references as non-owning observers unless ownership transfer is explicit
- Prefer standard library value types over raw arrays and manual bounds handling
- When helper functions take multiple adjacent same-shaped parameters, prefer a
small request struct if it improves clarity and avoids
bugprone-easily-swappable-parameters - Keep product/project terminology app-owned and consistent; reserve vendor- specific wording for vendor-boundary code
- Treat
clang-tidy, Doxygen, hygiene scripts, and CI as maintained checks, not optional extras - Prefer the repo-owned
clang-tidytarget from a configured build tree so the same compile database drives local and CI analysis - Keep analyzer fixes targeted to repo-owned code; do not churn vendored or generated output
- Prefer fixing code over weakening analyzer configuration
- In Qt-heavy variants, treat
misc-include-cleanerandreadability-redundant-access-specifiersas low-value noise unless the tool behavior improves - Prefer the repo-owned Valgrind runner over ad hoc Memcheck commands so leak policy and target selection stay aligned
- Treat third-party code as vendored/subtree-managed source
- Prefer app-side integration changes before touching vendored code
- If vendored code changes, document why and update provenance/notice files
- Do not commit generated binaries, model artifacts, or large release payloads
- Keep README, release checklist, workflows, install rules, and shipped assets aligned with each other
- Read
README.mdfirst, then the touched files before editing - Read
config/change-contract-policy.shwhen the work may trigger a substantive change contract - Prefer targeted changes over speculative cleanup
- Keep
README.md,AGENTS.md,.agents/skills/, scripts, and workflows aligned when the repo workflow changes - Store tracked feature plans under
feature_records/using the lifecycle subdirectory that matches the plan'sState; update the existing plan rather than scattering notes - Treat substantive repo-owned changes in
src/,tests/,scripts/,docs/,.github/workflows/,cmake/,benchmarks/,contrib/, and top-level build/release docs as contract-bearing work that should update a non-template feature plan unlessconfig/change-contract-policy.shnarrows or extends that set - Keep change-contract fields explicit:
missingevidence states are not acceptable, waived evidence requires rationale, and implementer/verifier identity matches require a self-validation waiver - Keep lifecycle state current so active, done, and superseded work can be
distinguished explicitly in
feature_records/ - Prefer
bash scripts/set-feature-record-lifecycle.sh <record> <state>when transitioning feature records between lifecycle folders - When moving a record to
superseded, provide a replacement path soSuperseded bystays explicit - Keep implementation notes owned by the implementer and verification notes owned by the verifier so the plan itself records the responsibility split
- Keep verifier notes concrete: record commands run, observed results, and any contract mismatches rather than only a summary sentence
- Do not leave generated artifacts in the repo tree
- Do not assume the workspace is a valid Git repo; if Git commands fail, continue with file-based validation and note the limitation
- Optimize for the current implementation, not hypothetical future platforms
- Prefer portable, buildable, testable defaults
- Ask before making architectural expansions that widen the frame far beyond a generic C++ project template