Contributing
Reqloom is Apache 2.0 and contributions are welcome. This page is the short version of what reviewers will look for.
Before you write code
Section titled “Before you write code”For anything more than a small fix, open an issue first. Two reasons: the change might already be planned, and the architecture has a hard boundary (the engine can’t depend on Qt UI) that’s easier to discuss before you’ve built around it.
Good first contributions:
- Documentation gaps — this site is generated from
docs-site/ - Closing a partial requirement from the roadmap
- New importer formats, which are self-contained
- Test coverage for an existing behaviour
git clone https://github.com/Mirzabaig313/Reqloomcd Reqloom./tools/setup-qt.shcmake --preset macos-debugcmake --build --preset macos-debugctest --test-dir build/macos-debug --output-on-failuregit config core.hooksPath tools/git-hooks # pre-push checksFull prerequisites: building from source.
Branches and commits
Section titled “Branches and commits”Branch from main. Never push directly to main.
Conventional commits, subject ≤ 70 characters:
feat(engine): add cookie extraction sourcefix(cli): report missing --var value instead of unknown argumentdocs(schema): document the !secret tagtest(engine): cover indexed reference out of rangerefactor(desktop): extract chain strip into its own componentchore(ci): pin Qt to 6.8.3perf(engine): avoid copying RunContext in the resolverci(release): mark alpha tags as prereleasesPrefixes: feat, fix, refactor, docs, test, chore, perf, ci.
The test rule
Section titled “The test rule”The one reviewers actually enforce:
Every bug fix lands with a test that reproduces the bug first. Domain-layer code targets 90%+ coverage; infrastructure coverage isn’t measured.
Test conventions:
TEST(RunBatchUseCase, fails_with_cycle_when_topology_invalid) { // Arrange FakeResolver resolver{ResolverFault::Cycle}; FakeRunner runner; RunBatchUseCase uc{resolver, runner}; RunContext ctx;
// Act const auto result = uc.execute({{"a"}, {"b"}}, ctx);
// Assert ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error(), ErrorCode::Cycle);}- File name mirrors the unit under test
- Test name is
<unit>_<observed_behaviour>insnake_case, describing what was observed, not what should happen - Arrange / Act / Assert separated by blank lines
- Use real engine types; fake only I/O
- Each test independent — no shared mutable state
- Use in-memory SQLite and the mock SUT fixtures rather than mocking the database
Code style
Section titled “Code style”clang-format and clang-tidy configs are in the repo:
tools/format.shThe conventions that come up most in review:
- C++23 only. No C++26 features — see language rules
std::expected<T, ReqloomError>for new error paths. Add to the existingErrorCodeenum, don’t create a parallel one- Brace every control flow block, even one-liners
std::print/std::println, neveriostreamchains orstd::endl- No C-style casts, no
NULL, notypedef, no rawnew/delete [[nodiscard]]on anything returningexpected,optional, orunique_ptrnoexcepton move constructors, move assignment, andswap- Files ≤ 800 lines, functions ≤ 50. Split rather than scroll
- Close namespaces with a comment —
} // namespace reqloom::engine
Qt-specific, for desktop/:
Q_OBJECTin anyQObjectsubclass using signals or slots- Function-pointer
connect()only — theSIGNAL()/SLOT()string form is banned - A lambda passed to
connect()needs a receiverQObject*so it disconnects on destruction Q_PROPERTYsetters early-return when the value is unchanged, then emit — or QML binding loops
Comments
Section titled “Comments”Comments explain why, not what. If a comment is needed to explain what the code does, simplify the code.
Required: a one-line purpose at the top of each file; a rationale on any
non-obvious algorithm; a justification on every NOLINT; what a magic number
means.
Not wanted: commented-out code, restatements of the obvious, trailing end-of-line
comments, banner separators inside functions, authorship notes, or TODOs without
an issue link. Write // TODO(#42): handle timeout retry or don’t write one.
Pull requests
Section titled “Pull requests”- Open against
mainfrom a feature branch - Title concise, under ~70 characters; details go in the description
- Say what you tested, not just what you changed
- Failing CI blocks merge
- Don’t commit secrets,
build/, or vcpkg trees —.gitignorecovers these, but check your staging area
If your change adds, completes, or breaks a documented behaviour, say so in the PR description with the file and the test name that proves it. Maintainers track requirement status separately, and a claim with no evidence reads as not done.
Documentation
Section titled “Documentation”The docs site is Astro Starlight under docs-site/:
cd docs-sitenpm installnpm run dev # http://localhost:4321Add a page under src/content/docs/<section>/, then add it to the sidebar in
astro.config.mjs. Frontmatter needs title and description.
One rule specific to these docs: verify against the binary, not the design docs. A
sizeable fraction of the original pages documented intended behaviour that was
never implemented — --dry-run, a secrets: block, $.random. If you document a
flag, run it first.
Reporting bugs
Section titled “Reporting bugs”Include the Reqloom version or commit, your OS, the schema (redacted), the command
you ran, and the output with the E_* code. A minimal reproducing schema is worth
more than a description.
Exit code 3 is always a bug — it means an unhandled exception escaped.
Security
Section titled “Security”Don’t open a public issue for a vulnerability. See
SECURITY.md.
The two attacker-controlled surfaces are schema parsing and spec import — changes there get extra scrutiny.
Licence
Section titled “Licence”Apache 2.0. The engine, CLI, schema, and desktop app are open source. The AI
importer prompt suite and the planned team-workspace sync are designated paid
components; don’t add closed-source-only code under the OSS tree without updating
LICENSE first.
- Architecture — read this before a structural change
- Building from source — presets, sanitizers, hooks
- Roadmap — the known gaps, if you want one to close