Contributing to Felix
How to get a change into Felix: what to build, what the checks demand, and what a good PR here looks like.
Code of Conduct
Section titled “Code of Conduct”Felix is an open and welcoming project. We expect all contributors to:
- Be respectful and considerate
- Focus on constructive feedback
- Help create a positive community
- Report unacceptable behavior to project maintainers
Ways to Contribute
Section titled “Ways to Contribute”Reporting Bugs
Section titled “Reporting Bugs”Found a bug? Please open an issue with:
- Clear title: Summarize the issue
- Description: What happened vs what you expected
- Reproduction steps: Minimal steps to reproduce
- Environment: OS, Rust version, Felix version
- Logs/errors: Relevant error messages or stack traces
Template:
**Bug Description**A clear description of the bug.
**To Reproduce**1. Start broker with config X2. Run client command Y3. Observe error Z
**Expected Behavior**What should have happened.
**Environment**- OS: Ubuntu 22.04- Rust: 1.97.1- Felix: main branch, commit abc123
**Logs**Paste relevant logs here
Suggesting Features
Section titled “Suggesting Features”Have an idea? Open an issue with:
- Problem statement: What problem does this solve?
- Proposed solution: How would it work?
- Alternatives considered: Other approaches you’ve thought about
- Additional context: Use cases, examples
Template:
**Problem**Describe the problem or limitation.
**Proposed Solution**How this feature would work.
**Alternatives**Other solutions considered and why they're less ideal.
**Use Case**Real-world scenario where this would help.Improving Documentation
Section titled “Improving Documentation”Documentation is always welcome! You can:
- Fix typos or clarify existing docs
- Add examples or tutorials
- Improve API documentation
- Write guides for common scenarios
See Building the Docs below.
Contributing Code
Section titled “Contributing Code”See Development Workflow for details.
Getting Started
Section titled “Getting Started”Prerequisites
Section titled “Prerequisites”- Rust 1.97.1+: Install via rustup
- Git: For version control
- Task (optional): Install from taskfile.dev
- Development tools:
cargo-fmt,cargo-clippy
Fork and Clone
Section titled “Fork and Clone”# Fork repository on GitHub# Then clone your forkgit clone https://github.com/YOUR_USERNAME/felix.gitcd felix
# Add upstream remotegit remote add upstream https://github.com/gabloe/felix.gitBuild and Test
Section titled “Build and Test”# Build everythingcargo build --workspace
# Run testscargo test --workspace
# Or use Tasktask buildtask testDevelopment Workflow
Section titled “Development Workflow”1. Create a Branch
Section titled “1. Create a Branch”# Sync with upstreamgit fetch upstreamgit checkout maingit merge upstream/main
# Create feature branchgit checkout -b feature/my-feature
# Or bugfix branchgit checkout -b fix/issue-123Branch naming:
feature/description: New featuresfix/description: Bug fixesdocs/description: Documentation changesrefactor/description: Code refactoringtest/description: Test additions/improvements
2. Make Changes
Section titled “2. Make Changes”Code style:
Felix follows standard Rust style guidelines:
# Format codecargo fmt --all
# Or with Tasktask fmtRun linter:
# Check formattingcargo fmt -- --check
# Run clippycargo clippy --workspace --all-targets --all-features -- -D warnings
# Or with Tasktask lintWriting tests:
All new code should include tests:
#[cfg(test)]mod tests { use super::*;
#[test] fn test_my_feature() { // Arrange let input = setup_test_data();
// Act let result = my_function(input);
// Assert assert_eq!(result, expected_value); }}Test async code:
#[tokio::test]async fn test_async_feature() { let result = my_async_function().await; assert!(result.is_ok());}3. Commit Changes
Section titled “3. Commit Changes”Commit message format:
<type>(<scope>): <subject>
<body>
<footer>Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Adding or modifying testschore: Build process or tooling changes
Example:
git add .git commit -m "feat(broker): add configurable batch timeout
Adds FELIX_EVENT_BATCH_MAX_DELAY_US configuration to controlthe maximum delay before flushing event batches. This allowsusers to tune the latency vs throughput trade-off.
Closes #123"Guidelines:
- Use present tense (“add” not “added”)
- Keep subject line under 72 characters
- Reference issues in footer (
Closes #123,Fixes #456) - Add breaking changes in footer:
BREAKING CHANGE: description
4. Push and Create PR
Section titled “4. Push and Create PR”# Push to your forkgit push origin feature/my-feature
# Create pull request on GitHubPull request template:
## DescriptionBrief description of changes.
## MotivationWhy is this change needed?
## Changes- List of changes made
## TestingHow was this tested?
## Checklist- [ ] Tests added/updated- [ ] Documentation updated- [ ] Ran `task lint`- [ ] Ran `task test`- [ ] No breaking changes (or documented in commit)5. Code Review
Section titled “5. Code Review”- Respond to feedback promptly
- Make requested changes in new commits
- Push updates to the same branch
- Request re-review when ready
6. Merge
Section titled “6. Merge”Once approved:
- Maintainers will merge your PR
- Delete your feature branch after merge
git checkout maingit pull upstream maingit branch -d feature/my-featureCode Style Guidelines
Section titled “Code Style Guidelines”Rust Style
Section titled “Rust Style”Follow standard conventions:
// Use descriptive namesfn calculate_batch_size(events: &[Event]) -> usize { ... }
// Document public APIs/// Publishes an event to the specified stream.////// # Arguments/// * `stream` - The target stream name/// * `payload` - The event payload////// # Returns/// Result indicating success or errorpub async fn publish(&self, stream: &str, payload: &[u8]) -> Result<()> { ... }
// Use Result for errorsfn parse_config(path: &str) -> Result<Config> { ... }
// Prefer ? operator over unwrap()let config = parse_config(path)?;
// Use meaningful error messagesreturn Err(anyhow!("Failed to bind to {}: {}", addr, err));Formatting
Section titled “Formatting”# Format all codecargo fmt --all
# Check formatting in CIcargo fmt -- --checkLinting
Section titled “Linting”# Run clippycargo clippy --workspace --all-targets --all-features -- -D warnings
# Fix automatically where possiblecargo clippy --fixComments
Section titled “Comments”When to comment:
- Complex algorithms
- Non-obvious design decisions
- Performance-critical sections
- Workarounds for external issues
When not to comment:
- Obvious code
- What the code does (code should be self-documenting)
// Good: Explains why// We batch events to amortize framing overhead across multiple messages.// Empirical testing shows 64 events per batch optimizes for 1-4KB payloads.const DEFAULT_BATCH_SIZE: usize = 64;
// Bad: Restates the obvious// Set the batch size to 64const DEFAULT_BATCH_SIZE: usize = 64;Error Handling
Section titled “Error Handling”// Use anyhow for application codeuse anyhow::{Context, Result};
fn load_config(path: &str) -> Result<Config> { let contents = fs::read_to_string(path) .with_context(|| format!("Failed to read config from {}", path))?; let config: Config = serde_yaml_ng::from_str(&contents) .context("Failed to parse config YAML")?; Ok(config)}
// Use custom error types for libraries#[derive(Debug, thiserror::Error)]pub enum BrokerError { #[error("Connection closed")] ConnectionClosed, #[error("Invalid frame: {0}")] InvalidFrame(String),}Testing Guidelines
Section titled “Testing Guidelines”Test Coverage
Section titled “Test Coverage”- All public APIs must have tests
- Bug fixes must include regression tests
- Aim for >80% code coverage
Test Organization
Section titled “Test Organization”#[cfg(test)]mod tests { use super::*;
// Unit tests for internal functions #[test] fn test_parse_frame() { ... }
// Integration tests for APIs #[tokio::test] async fn test_publish_subscribe_flow() { ... }}Running Tests
Section titled “Running Tests”# All testscargo test --workspace
# Specific testcargo test test_name
# With outputcargo test -- --nocapture
# With coveragetask coverageTest Fixtures
Section titled “Test Fixtures”// Create reusable test helpersfn create_test_broker() -> Broker { BrokerBuilder::new() .with_config(test_config()) .build() .unwrap()}
#[tokio::test]async fn test_feature() { let broker = create_test_broker(); // Test code}Documentation
Section titled “Documentation”Code Documentation
Section titled “Code Documentation”/// A brief one-line summary.////// More detailed description if needed. Can span multiple paragraphs.////// # Arguments/// * `arg1` - Description of arg1/// * `arg2` - Description of arg2////// # Returns/// Description of return value////// # Errors/// Description of error conditions////// # Examples/// ```/// use felix_broker::Broker;////// let broker = Broker::new();/// broker.start().await?;/// ```pub async fn my_function(arg1: Type1, arg2: Type2) -> Result<Type3> { // Implementation}Building Documentation
Section titled “Building Documentation”API docs:
# Build and open docscargo doc --open --no-deps
# Build all docscargo doc --workspaceUser documentation:
# Install dependencies and serve locallycd docs-sitenpm installnpm run dev
# Build static sitenpm run buildPerformance Considerations
Section titled “Performance Considerations”Benchmarking
Section titled “Benchmarking”# Run latency benchmarkscargo run --release -p broker --bin latency-demo -- \ --binary --fanout 10 --batch 64 --payload 4096
# Run cache benchmarkscargo run --release -p broker --bin cache-demoProfiling
Section titled “Profiling”CPU profiling:
# Linux perfsudo perf record -g cargo run --release -p brokersudo perf report
# Flamegraphcargo install flamegraphcargo flamegraph -p brokerMemory profiling:
# Valgrind (debug build)valgrind --leak-check=full ./target/debug/broker
# Heaptrack (Linux)heaptrack cargo run --release -p brokerRelease Process
Section titled “Release Process”(For maintainers)
- Update version in
Cargo.toml - Update
CHANGELOG.md - Create git tag:
git tag -a v0.1.0 -m "Release v0.1.0" - Push tag:
git push origin v0.1.0 - GitHub Actions builds and publishes release
Getting Help
Section titled “Getting Help”Stuck?
- GitHub Discussions: Ask questions
- GitHub Issues: Bug reports and feature requests
- Documentation: docs-site/
Before asking:
- Check existing issues/discussions
- Review documentation
- Try to create a minimal reproduction
Recognition
Section titled “Recognition”Contributors are recognized in:
CONTRIBUTORS.md(added on first merged PR)- Release notes
- GitHub contributors graph
Thank you for contributing to Felix! 🎉
Next Steps
Section titled “Next Steps”- Build system: Building & Testing Guide
- Project structure: Project Structure
- Architecture: System Design
