Contributing
Thank you for your interest in contributing to Rix.
Rix is the official userland package layer for Vix.cpp. It provides optional libraries such as auth, CSV, debug helpers, PDF generation, and future packages for Vix.cpp applications.
This guide explains how to contribute to Rix packages, examples, documentation, tests, and package design.
The short version
Use Vix commands:
vix install
vix build
vix testsFor package dependencies, use deps in vix.app:
deps = [
"rix/rix",
]Do not put Rix packages in packages.
Keep Rix packages:
optional
focused
stable
independent
easy to use from Vix.cpp projectsProject goals
Rix exists to keep Vix.cpp focused.
Vix.cpp owns:
runtime
CLI
project workflow
build workflow
registry workflow
application foundation
service and deployment workflowRix owns optional userland libraries:
auth
csv
debug
pdf
future packagesA contribution should respect that separation.
What Rix is
Rix is an official package namespace and collection for optional Vix.cpp libraries.
Rix packages are installed through the Vix Registry:
vix add rix/rix
vix installThey are used through deps:
deps = [
"rix/rix",
]What Rix is not
Rix is not a CLI.
Rix is not a runtime.
Rix is not the package manager.
Rix is not Vix Core.
Rix is not a standard library built into Vix.cpp.
Rix packages are optional libraries used inside Vix.cpp projects.
Package model
Every Rix package should follow one stable model:
Registry package -> rix/name
Header -> <rix/name.hpp>
Facade access -> rix.name
Namespace -> rixlib::nameExamples:
rix/auth -> <rix/auth.hpp> -> rix.auth -> rixlib::auth
rix/csv -> <rix/csv.hpp> -> rix.csv -> rixlib::csv
rix/debug -> <rix/debug.hpp> -> rix.debug -> rixlib::debug
rix/pdf -> <rix/pdf.hpp> -> rix.pdf -> rixlib::pdfThe unified facade package is:
rix/rixIt provides:
#include <rix.hpp>and:
rix.auth
rix.csv
rix.debug
rix.pdfContribution areas
You can contribute by improving:
package APIs
bug fixes
tests
examples
documentation
README files
registry metadata
error messages
security notes
package designStart small when possible.
A focused fix is easier to review than a large mixed change.
Before contributing
Make sure the project builds:
vix install
vix buildRun tests:
vix testsRun relevant examples:
vix run examples/01_basic.cppUse Vix commands for Rix projects.
Do not use direct CMake or Ninja commands unless you are specifically debugging build internals.
Repository setup
Clone the repository:
git clone https://github.com/rixcpp/rix.git
cd rixInstall dependencies:
vix installBuild:
vix buildRun tests:
vix testsBranch naming
Use short branch names.
Examples:
fix/pdf-save-error
docs/auth-security
feat/csv-options
test/debug-formatKeep one topic per branch.
Commit style
Use clear commit messages.
Examples:
fix(pdf): handle empty output path
docs(auth): add session security notes
test(csv): cover row filter options
feat(debug): add format append helperGood commit messages explain the package and the reason.
Code style
Keep code simple and explicit.
Prefer readable APIs over clever abstractions.
Use C++20.
Use clear names.
Keep public APIs small.
Keep implementation details hidden.
Prefer explicit result types for expected failures.
Include style
Public includes should use Rix package headers.
Facade usage:
#include <rix.hpp>Independent package usage:
#include <rix/pdf.hpp>
#include <rix/csv.hpp>
#include <rix/debug.hpp>
#include <rix/auth.hpp>Do not require users to include internal headers for normal workflows.
Namespace style
Use package namespaces:
namespace rixlib::pdf
{
}Examples:
rixlib::auth
rixlib::csv
rixlib::debug
rixlib::pdfThe global facade object exposes modules:
rix.auth
rix.csv
rix.debug
rix.pdfPublic API design
Public APIs should make common workflows short.
Good:
auto doc = rix.pdf.document();
auto &page = doc.add_page();
page.text(
page.x_left(),
page.y_top(),
"Hello from rix.pdf");
auto saved = rix.pdf.save(doc, "hello.pdf");Avoid making users start from internals.
Less good as a first API:
PdfObjectWriter writer;
XrefTable xref;
FontRegistry fonts;Internals can exist, but the common public API should stay simple.
Error handling
Expected failures should use explicit result or status objects.
For operations that return values:
auto bytes = rix.pdf.write(doc);
if (bytes.failed())
{
rix.debug.eprint(
"pdf error:",
rix.pdf.error.to_string(bytes.error()),
bytes.error().message());
return 1;
}
const auto &data = bytes.value();For operations that only succeed or fail:
auto saved = rix.pdf.save(doc, "output.pdf");
if (saved.failed())
{
rix.debug.eprint(
"pdf error:",
rix.pdf.error.to_string(saved.error()),
saved.error().message());
return 1;
}Never call value() before checking success.
Error codes
Packages with domain failures should expose stable error codes.
Examples:
rixlib::auth::AuthErrorCode
rixlib::pdf::PdfErrorCodeError helpers should be exposed through package modules:
rix.auth.error.to_string(error)
rix.auth.error.is(error, code)
rix.pdf.error.to_string(error)
rix.pdf.error.is(error, code)Use stable error codes for application decisions.
Use error messages for diagnostics.
Security-sensitive code
Be careful with packages related to auth, passwords, sessions, tokens, crypto, or user data.
Do not log:
plain-text passwords
password hashes
raw tokens
session ids
private keys
secretsAuth changes should keep safe defaults.
Security-sensitive code should have tests and documentation.
Debug output
rix.debug is useful for examples, tests, formatting, printing, and inspection.
For real Vix application logs, prefer:
vix::logDo not design production application logging around:
rix.debug.logUse debug helpers for examples and small tools.
Dependencies
Rix packages belong in deps.
Correct:
deps = [
"rix/pdf",
]Wrong:
packages = [
"rix/pdf",
]deps is for Vix Registry dependencies.
packages is for CMake package discovery.
Adding dependencies
If a package needs another Rix package, add it explicitly.
Example:
deps = [
"rix/debug",
]Independent packages should avoid depending on rix/rix unless there is a strong reason.
If a package only needs one feature, depend on that package directly.
Facade changes
When adding a package to the unified facade, make sure:
the independent package works first
the facade member name follows rix.name
the package has a stable public module
feature macros still work
default facade behavior still works
docs are updated
examples are updated
tests are addedFeature macros
The facade supports feature macros.
If no feature macro is defined, all mounted modules are enabled.
If one or more feature macros are defined, only selected modules are mounted.
Examples:
#define RIX_ENABLE_PDF
#include <rix.hpp>#define RIX_ENABLE_CSV
#define RIX_ENABLE_DEBUG
#include <rix.hpp>Available macros include:
RIX_ENABLE_AUTH
RIX_ENABLE_CSV
RIX_ENABLE_DEBUG
RIX_ENABLE_PDFWhen adding a new facade module, add its feature macro and test it.
Documentation style
Docs should start with the facade when possible:
#include <rix.hpp>and:
rix.pdf
rix.auth
rix.csv
rix.debugThen show independent usage later:
#include <rix/pdf.hpp>
auto pdf = rixlib::pdf::module();This keeps the public docs consistent.
Documentation should avoid /tmp
Use home-folder examples:
mkdir -p ~/rix-example
cd ~/rix-exampleDo not use /tmp in docs unless there is a specific reason.
Some systems or user environments may not behave the same with /tmp.
Example style
Examples should be complete and runnable.
Good example:
#include <rix.hpp>
int main()
{
auto doc = rix.pdf.document();
auto &page = doc.add_page();
page.text(
page.x_left(),
page.y_top(),
"Hello from rix.pdf");
auto saved = rix.pdf.save(doc, "hello.pdf");
if (saved.failed())
{
rix.debug.eprint(
"pdf error:",
rix.pdf.error.to_string(saved.error()),
saved.error().message());
return 1;
}
rix.debug.print("created:", "hello.pdf");
return 0;
}Run examples with:
vix run example.cppIf Rix is not available globally:
vix install -g rix/rix
vix run example.cppVix project examples
For project examples, use:
vix new my-app --app
cd my-app
vix add rix/rix
vix install
vix build
vix runShow deps clearly:
deps = [
"rix/rix",
]Do not put Rix packages in packages.
Tests
Add tests for code changes.
Tests should cover:
basic success path
invalid input
edge cases
error codes
public headers
version helpers
result handling
facade usage when relevant
independent usage when relevantRun:
vix testsExamples
Add examples when a feature needs explanation.
Examples should show real usage, not internals first.
For PDF:
examples/pdf/basic
examples/pdf/text
examples/pdf/table
examples/pdf/drawing
examples/pdf/error-handlingFor auth:
examples/auth/memory-register-login
examples/auth/password-hash
examples/auth/session-refresh-logout
examples/auth/token-issueFor CSV and debug:
examples/csv
examples/debugREADME updates
Update the README when a contribution changes public behavior.
A README should explain:
what the package does
how to install it
how to include it
a basic example
facade usage
independent usage
error handling when relevant
license
repository linkStart with public usage.
Do not start with internals.
Changelog updates
If the repository uses a changelog, update it for user-facing changes.
Group changes by type:
Added
Changed
Fixed
Deprecated
Removed
SecurityKeep entries short and clear.
Pull request checklist
Before opening a pull request, check:
vix install passes
vix build passes
vix tests passes
examples still run
docs are updated
README is updated if needed
public API is stable and simple
errors are explicit
sensitive values are not logged
Rix packages are in deps, not packagesPull request description
A good pull request description includes:
what changed
why it changed
how it was tested
any API impact
any documentation impact
any security impactExample:
## Summary
Fixes PDF save error handling for empty output paths.
## Testing
- vix build
- vix tests
- vix run examples/pdf/error_handling.cpp
## Notes
No breaking API changes.Reviewing contributions
Reviews should focus on:
correctness
API simplicity
error handling
test coverage
docs clarity
security implications
Vix/Rix separation
backward compatibilityPrefer specific feedback.
Avoid broad rewrites unless they improve the public API or correctness.
Backward compatibility
Avoid breaking public APIs without a strong reason.
If a breaking change is necessary:
explain why
update docs
update examples
update tests
consider a migration note
use a version bump that reflects the changeKeep application code stable.
Adding a new package
Before adding a new Rix package, check:
Does it solve one clear problem?
Is it optional?
Does it belong outside Vix Core?
Can it work independently?
Can it later mount into rix/rix?
Does it follow rix/name?
Does it expose <rix/name.hpp>?
Does it use namespace rixlib::name?
Does it have a simple module?
Does it have examples and tests?If the answer is yes, it fits the Rix model.
New package structure
A new package can use this shape:
name/
CMakeLists.txt
README.md
LICENSE
vix.json
include/
rix/
name.hpp
name/
Version.hpp
NameModule.hpp
core/
detail/
src/
NameModule.cpp
examples/
01_basic.cpp
tests/
name_tests.cppPackage header
Every package should expose:
#include <rix/name.hpp>Example shape:
#ifndef RIXCPP_NAME_INCLUDE_RIX_NAME_HPP_INCLUDED
#define RIXCPP_NAME_INCLUDE_RIX_NAME_HPP_INCLUDED
#include <rix/name/NameModule.hpp>
#include <rix/name/Version.hpp>
namespace rixlib::name
{
[[nodiscard]] inline constexpr NameModule module() noexcept
{
return NameModule{};
}
}
#endifVersion helpers
Packages should expose version helpers.
Example:
rix.name.version()
rix.name.version_major()
rix.name.version_minor()
rix.name.version_patch()
rix.name.version_number()Independent package namespace:
rixlib::name::version()
rixlib::name::version_major()
rixlib::name::version_minor()
rixlib::name::version_patch()
rixlib::name::version_number()Release checklist
Before a release:
update version
update changelog
run vix install
run vix build
run vix tests
run examples
check docs
check README
tag release
publish registry metadata
test install from a clean projectAfter publishing, verify:
vix registry sync
vix add rix/name
vix installSecurity issues
Do not open a public issue for sensitive security problems.
Report security problems privately through the project maintainer contact or the repository security policy if one is available.
Security-sensitive reports may include:
auth bypass
password hashing issues
token leakage
session validation issues
secret exposure
unsafe defaultsCommon mistakes
Putting Rix dependencies in packages
Wrong:
packages = [
"rix/rix",
]Correct:
deps = [
"rix/rix",
]Using direct CMake commands in docs
Prefer Vix commands:
vix build
vix tests
vix runStarting docs from internals
Start from public usage:
#include <rix.hpp>
auto doc = rix.pdf.document();Then document internals later if needed.
Calling Rix a runtime
Rix is not the runtime.
Vix.cpp owns runtime behavior.
Calling Rix a package manager
Rix is not the package manager.
Vix owns the package workflow.
Logging secrets
Do not log:
passwords
password hashes
tokens
session ids
private keys
secretsUsing /tmp in docs
Prefer:
mkdir -p ~/rix-exampleover:
mkdir -p /tmp/rix-exampleWhat you should remember
Use Vix commands:
vix install
vix build
vix testsUse deps for Rix packages:
deps = [
"rix/rix",
]Follow the Rix package model:
Registry package -> rix/name
Header -> <rix/name.hpp>
Facade access -> rix.name
Namespace -> rixlib::nameKeep packages independent.
Keep public APIs small.
Use explicit results for expected failures.
Document facade usage first.
Do not log sensitive values.
Next step
Read the package model and package checklist.
Next: Package model