Contributing¶
Thank you for your interest in contributing to Mullama. This guide covers the development environment setup, code standards, testing practices, and the contribution workflow.
Getting Started¶
1. Fork and Clone¶
Fork the repository on GitHub, then clone with submodules (required for llama.cpp):
If you already cloned without --recursive:
2. Create a Feature Branch¶
Always work on a feature branch:
Development Environment Setup¶
System Dependencies¶
# Audio libraries
sudo apt install -y libasound2-dev libpulse-dev libflac-dev libvorbis-dev libopus-dev
# Image libraries
sudo apt install -y libpng-dev libjpeg-dev libtiff-dev libwebp-dev
# Video/FFmpeg libraries
sudo apt install -y ffmpeg libavcodec-dev libavformat-dev libavutil-dev
# Build tools
sudo apt install -y build-essential cmake pkg-config
Rust Toolchain¶
Ensure you have the latest stable Rust:
GPU Development (Optional)¶
For GPU-accelerated development, set the appropriate environment variable before building:
# NVIDIA CUDA
export LLAMA_CUDA=1
# Apple Metal (macOS)
export LLAMA_METAL=1
# AMD ROCm
export LLAMA_HIPBLAS=1
# OpenCL
export LLAMA_CLBLAST=1
Building from Source¶
Quick Build Check¶
# Verify core compiles (no features)
cargo check --no-default-features
# Verify with specific features
cargo check --features "async,streaming"
cargo check --features "multimodal,streaming-audio"
cargo check --features "web,websockets"
Full Build¶
# Debug build with all features
cargo build --features full
# Release build
cargo build --release --features full
Building the Daemon¶
# CLI daemon
cargo build --release --features daemon
# Daemon with embedded Web UI
cd ui && npm install && npm run build && cd ..
cargo build --release --features daemon,embedded-ui
Running Tests¶
Unit Tests¶
# Basic tests (no model required)
cargo test
# Full test suite with all features
cargo test --features full
# Tests for a specific module
cargo test --lib sampling
cargo test --lib embedding
# With output visible
cargo test -- --nocapture
Integration Tests¶
Integration tests may require a model file. Set the MULLAMA_TEST_MODEL environment variable:
Verifying Examples Compile¶
# Ensure all examples compile
cargo build --examples --features full
# Run a specific example
cargo run --example simple --features async
cargo run --example embedding
Code Style¶
Formatting¶
Always run cargo fmt before committing:
The project uses the default Rust formatting style.
Linting¶
Run clippy with all features enabled and treat warnings as errors:
Address all warnings before submitting a PR. Common clippy suggestions include:
- Use
if letinstead of single-armmatch - Prefer
&strover&Stringin function parameters - Use
Default::default()where appropriate - Avoid redundant closures
Safety Rules¶
- No
unsafein public API surface -- All unsafe operations must be encapsulated within safe wrappers in internal modules - Document unsafe blocks -- Every
unsafeblock must have a// SAFETY:comment explaining why it is sound - Minimize unsafe scope -- Keep unsafe blocks as small as possible
// Good: Minimal unsafe scope with safety documentation
pub fn vocab_size(&self) -> i32 {
// SAFETY: self.model is a valid pointer initialized in Model::load()
// and remains valid for the lifetime of the Model struct
unsafe { llama_n_vocab(self.model) }
}
Error Handling¶
- Use
MullamaErrorfor all public functions returningResult - Never panic (
unwrap(),expect(),panic!()) in library code - Include context in error messages about what went wrong
// Good: Descriptive error with context
pub fn load(path: &str) -> Result<Self, MullamaError> {
if !std::path::Path::new(path).exists() {
return Err(MullamaError::ModelLoadError(
format!("Model file not found: {}", path)
));
}
// ...
}
Documentation Standards¶
- All public types, functions, and modules must have doc comments (
///) - Include usage examples in doc comments where helpful
- Use
//!for module-level documentation
/// Load a GGUF model from the filesystem.
///
/// # Arguments
///
/// * `path` - Path to the GGUF model file
///
/// # Errors
///
/// Returns `MullamaError::ModelLoadError` if the file cannot be opened
/// or is not a valid GGUF format.
///
/// # Example
///
/// ```no_run
/// use mullama::Model;
/// let model = Model::load("path/to/model.gguf")?;
/// ```
pub fn load(path: &str) -> Result<Self, MullamaError> {
// ...
}
Feature-Gated Code¶
When adding code that depends on optional features:
// Gate the module
#[cfg(feature = "streaming")]
pub mod streaming;
// Gate imports
#[cfg(feature = "async")]
use tokio::runtime::Runtime;
// Gate implementations
#[cfg(feature = "web")]
impl AppState {
pub fn create_router(self) -> axum::Router {
// ...
}
}
Always provide helpful error messages when features are missing:
#[cfg(not(feature = "multimodal"))]
pub fn process_image(_path: &str) -> Result<(), MullamaError> {
Err(MullamaError::FeatureDisabled(
"The 'multimodal' feature is required for image processing. \
Build with: cargo build --features multimodal".to_string()
))
}
Pull Request Process¶
Before Submitting¶
- Run the full check suite:
cargo fmt
cargo clippy --features full -- -D warnings
cargo test --features full
cargo build --features full
-
Update documentation if your change affects the public API.
-
Add tests for new functionality.
-
Keep commits focused -- one logical change per commit.
PR Description Template¶
Include in your PR description:
- What -- Brief summary of the changes
- Why -- Motivation and context
- How -- Approach taken (for non-trivial changes)
- Testing -- How you verified the changes work
- Breaking changes -- Any API changes that affect existing users
Review Criteria¶
PRs are reviewed for:
- [ ] Code compiles with
--features full - [ ] All tests pass
- [ ] No clippy warnings
- [ ] Code is formatted with
cargo fmt - [ ] Public API changes are documented
- [ ] No unsafe code in public API
- [ ] Error handling uses
MullamaError(no panics) - [ ] New features are properly gated behind feature flags
- [ ] Commit messages are clear and descriptive
Documentation Contributions¶
The documentation uses MkDocs Material.
Setup¶
cd documentation
# Install dependencies
pip install mkdocs-material
# Local preview with live reload
mkdocs serve
# Build static site
mkdocs build
Writing Guidelines¶
- Use clear, concise language
- Include code examples for all API descriptions
- Use admonitions (
!!! note,!!! warning,!!! tip) for callouts - Parameter tables use format: Name | Type | Default | Description
- Test all code examples mentally for correctness
- Cross-reference related pages with relative links
File Organization¶
documentation/docs/
index.md # Landing page
getting-started/ # Installation, quickstart
guide/ # Conceptual guides
api/ # API reference (type signatures, parameters)
examples/ # Complete runnable examples
advanced/ # Advanced topics
bindings/ # Language binding docs
daemon/ # Daemon documentation
Reporting Issues¶
Bug Reports¶
When reporting bugs, include:
- Rust version (
rustc --version) - Platform (OS, architecture, GPU if relevant)
- Mullama version (commit hash or release tag)
- Feature flags used
- Minimal reproduction -- smallest code that triggers the issue
- Expected vs. actual behavior
- Error messages -- full output including any backtraces
# Gather debug info
rustc --version
cargo --version
uname -a # or systeminfo on Windows
git log -1 --format="%H"
Feature Requests¶
For feature requests, describe:
- Use case -- What you are trying to accomplish
- Current workaround -- How you handle it today (if applicable)
- Proposed solution -- Your suggested approach
- Alternatives considered -- Other approaches you thought about
Binding Development¶
Mullama supports language bindings via FFI, N-API, PyO3, and CGo.
Adding a New Binding¶
- Create a directory under
bindings/(e.g.,bindings/ruby/) - Implement the FFI wrapper using the C API from
bindings/ffi/ - Add type mappings for the target language
- Write tests that exercise the core API through the binding
- Add documentation in
documentation/docs/bindings/
Updating Existing Bindings¶
When the Rust API changes:
- Update the C FFI layer in
bindings/ffi/ - Regenerate or update each language binding
- Update binding tests
- Update binding documentation
Binding Architecture¶
bindings/
ffi/ # C header and implementation (base layer)
node/ # Node.js via N-API (napi-rs)
python/ # Python via PyO3
go/ # Go via CGo
php/ # PHP via FFI
Release Process Overview¶
Releases follow semantic versioning:
- Version bump -- Update
Cargo.tomlversion - Changelog -- Document changes since last release
- CI checks -- All tests pass on Linux, macOS, Windows
- Tag -- Create annotated git tag:
git tag -a v0.x.y -m "Release v0.x.y" - Publish --
cargo publish(maintainers only) - Bindings -- Update and publish language binding packages
Code of Conduct¶
All contributors are expected to follow the Rust Code of Conduct. We are committed to providing a welcoming and inclusive experience for everyone.
Key points:
- Be respectful and constructive in all interactions
- Focus on technical merit in code reviews
- Welcome newcomers and help them get started
- Report unacceptable behavior to project maintainers
Getting Help¶
- Open a GitHub Issue for bugs or feature requests
- Check existing issues before creating new ones
- For usage questions, refer to the Examples section
- Review the API Reference for type details
Thank you for contributing to Mullama.