Contributing to Felix
This page summarises CONTRIBUTING.md, which is the canonical text. Read it before your first pull request.
Licensing
Section titled “Licensing”Felix is split-licensed. The wire protocol, transport, client SDKs and
felix-common are Apache-2.0. The broker, the server libraries, the control
plane and the test tooling are AGPL-3.0-only.
LICENSING.md has the
table of which path is under which licence. task publish:check fails CI if a
crate’s manifest drifts from that table, or if an Apache-2.0 crate depends on
an AGPL one. Know which side your change lands on before you start.
Sign-off and CLA
Section titled “Sign-off and CLA”Every contribution needs both:
-
A DCO sign-off on each commit. Commit with
-s, which adds aSigned-off-by:trailer:Terminal window git commit -s -m "your message" -
A CLA grant, once. On your first pull request the CLA Assistant bot (
.github/workflows/cla.yml) asks you to reply with a fixed phrase. The text is in CLA.md. You keep your copyright.
AI-assisted changes
Section titled “AI-assisted changes”AI tools are fine to use. You are responsible for what you submit, so review generated code as if you wrote it. Disclose substantial AI assistance in the PR description. A line such as “drafted with Claude Code, reviewed and tested by me” is enough.
How the code is organised
Section titled “How the code is organised”Reviewers hold changes to these rules. The full list is in CONTRIBUTING.md under “How the code is organized”. Project Structure shows the layout they produce.
- Crates are grouped by role under
crates/(protocol,server,sdk,testing). Deployables live inservices/. Directories are named after the package. - One module style:
foo.rswith its children infoo/. Nomod.rs(clippy’smod_module_filesenforces this), no#[path]. lib.rsis a table of contents: crate docs, module declarations and re-exports.- Name modules by what they are about, not by kind of code. No
utils,helpersortypes. - Default to
pub(crate). Theunreachable_publint catches apubthat nothing outside the crate uses. - Unit tests go in
<module>/tests.rs, declared as#[cfg(test)] mod tests;at the bottom of the module. Integration tests go in the crate’stests/. - A decoder that reads bytes from outside the process gets a fuzz target. See Fuzzing.
- Shared dependency versions go in
[workspace.dependencies]. Members add features and never re-pin a version.
Comments
Section titled “Comments”Comment the reason, briefly. An ordering requirement, a failure mode or a limit
that exists for a reason deserves a sentence next to the code that depends on
it. Don’t restate what the code says, and don’t narrate history. If an
explanation needs paragraphs, put it in docs/ and point to it from the code.
// Offsets are claimed before waiting on durability, so the batch keeps its// place in the stream's order even while an earlier publish is still flushing.let pending = log.begin_append(&payloads).await?;/// on a public item is documentation: say what the item does and what it
guarantees, and keep it accurate.
Add tests for new behaviour. For a concurrency or durability fix, revert the fix, watch the new test fail, then restore it. A regression test that passes without the fix proves nothing.
Changes to cluster behaviour need a cluster test, and changes to the modelled replication protocol need the TLA+ model to follow. See How Felix Is Tested.
Docs ship with the change
Section titled “Docs ship with the change”docs/ and this site make specific claims about what is implemented. If you
ship a capability, update the pages that describe it in the same PR, including
the status table in
What Felix Is For. If you find a
claim the code cannot back, fix the claim. task docs:evidence checks that
cited tests and FELIX_* variable names still exist.
Before you open a PR
Section titled “Before you open a PR”task lint # fmt check, workspace clippy -D warnings, per-crate feature checkstask test # the workspace tests, with Postgres when Docker or Podman is availabletask docs:evidence # doc citations and env-var namestask demo:check # if you changed a public API the standalone demos useCI runs more than these; Building & Testing lists every job. Keep PRs focused. A bug fix does not need an unrelated refactor riding along.
Releases
Section titled “Releases”A release is cut by pushing a v* tag, and .github/workflows/release.yml
builds and publishes it. The workspace, the Python wheel, the npm package and
the Helm chart each carry their own version, so run
task release:check -- v<version> first to confirm they all match the tag.
Before tagging, try the latest nightly build,
which is main as of last night, built the way a release is.
