Contributing

🀝 Guidelines for contributing to PiSovereign

Thank you for your interest in contributing to PiSovereign! This guide will help you get started.

Table of Contents


Code of Conduct

This project adheres to a Code of Conduct. By participating, you are expected to:

  • Be respectful and inclusive
  • Accept constructive criticism gracefully
  • Focus on what’s best for the community
  • Show empathy towards others

Development Setup

Prerequisites

RequirementVersionNotes
Rust1.93.0+Edition 2024
JustLatestCommand runner
SQLite3.xDevelopment database
FFmpeg5.x+Audio processing

Environment Setup

  1. Clone the repository
git clone https://github.com/twohreichel/PiSovereign.git
cd PiSovereign
  1. Install Rust toolchain
# Install rustup if needed
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Install required components
rustup component add rustfmt clippy

# Install nightly for docs (optional)
rustup toolchain install nightly
  1. Install Just
# macOS
brew install just

# Linux
cargo install just
  1. Install development dependencies
# macOS
brew install sqlite ffmpeg

# Ubuntu/Debian
sudo apt install libsqlite3-dev ffmpeg pkg-config libssl-dev
  1. Verify setup
# Run quality checks
just quality

# Build the project
just build

Running Tests

# Run all tests
just test

# Run tests with output
just test-verbose

# Run specific crate tests
cargo test -p domain
cargo test -p application

# Run integration tests
cargo test --test '*' -- --ignored

# Generate coverage report
just coverage

Code Style

Rust Formatting

We use rustfmt with custom configuration:

# Format all code
just fmt

# Check formatting (CI will fail if not formatted)
just fmt-check

Configuration in rustfmt.toml:

edition = "2024"
max_width = 100
use_small_heuristics = "Default"
imports_granularity = "Crate"
group_imports = "StdExternalCrate"

Clippy Lints

We enforce strict Clippy lints:

# Run clippy
just lint

# Auto-fix issues
just lint-fix

Key lint categories enabled:

  • clippy::pedantic - Strict lints
  • clippy::nursery - Experimental but useful lints
  • clippy::cargo - Cargo.toml best practices

Commit Messages

We follow Conventional Commits:

<type>(<scope>): <description>

[optional body]

[optional footer(s)]

Types:

TypeDescription
featNew feature
fixBug fix
docsDocumentation only
styleCode style (formatting, no logic change)
refactorCode change that neither fixes nor adds
perfPerformance improvement
testAdding or updating tests
choreMaintenance tasks

Examples:

feat(api): add streaming chat endpoint

Implements SSE-based streaming for /v1/chat/stream endpoint.
Supports token-by-token response streaming for better UX.

Closes #123
fix(inference): handle timeout gracefully

Previously, inference timeouts caused a panic. Now returns
a proper error response with retry information.

Documentation

All public APIs must be documented:

/// Processes a user message and returns an AI response.
///
/// This method handles the full conversation flow including:
/// - Loading conversation context
/// - Calling the inference engine
/// - Persisting the response
///
/// # Arguments
///
/// * `conversation_id` - Optional ID to continue existing conversation
/// * `message` - The user's message content
///
/// # Returns
///
/// Returns the AI's response or an error if processing fails.
///
/// # Errors
///
/// - `ServiceError::Inference` - If the inference engine is unavailable
/// - `ServiceError::Database` - If conversation persistence fails
///
/// # Examples
///
/// ```rust,ignore
/// let response = service.send_message(
///     Some(conversation_id),
///     "What's the weather?".to_string(),
/// ).await?;
/// ```
pub async fn send_message(
    &self,
    conversation_id: Option<ConversationId>,
    message: String,
) -> Result<Message, ServiceError> {
    // ...
}

Pull Request Process

Before You Start

  1. Check existing issues/PRs

    • Look for related issues or PRs
    • Comment on the issue you want to work on
  2. Create an issue first (for features)

    • Describe the feature
    • Discuss approach before implementing
  3. Fork and branch

    git checkout -b feat/my-feature
    # or
    git checkout -b fix/issue-123
    

Creating a PR

  1. Ensure quality checks pass

    just pre-commit
    
  2. Write/update tests

    • Add tests for new functionality
    • Ensure existing tests still pass
  3. Update documentation

    • Update relevant docs in docs/
    • Add doc comments to new public APIs
  4. Push and create PR

    git push origin feat/my-feature
    
  5. Fill out PR template

    • Description of changes
    • Related issues
    • Testing performed
    • Breaking changes (if any)

PR Template

## Description
Brief description of what this PR does.

## Related Issues
Fixes #123
Related to #456

## Type of Change
- [ ] Bug fix (non-breaking)
- [ ] New feature (non-breaking)
- [ ] Breaking change
- [ ] Documentation update

## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manually tested on Raspberry Pi

## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] No new warnings

Review Process

  1. Automated checks must pass:

    • Format check (rustfmt)
    • Lint check (clippy)
    • Tests (all platforms)
    • Coverage (no significant decrease)
    • Security scan (cargo-deny)
  2. Human review:

    • At least one maintainer approval required
    • Address all review comments
  3. Merge:

    • Squash and merge for clean history
    • Delete branch after merge

Development Workflow

Common Tasks

# Full quality check (run before pushing)
just quality

# Quick pre-commit check
just pre-commit

# Run the server locally
just run

# Run CLI commands
just cli status
just cli chat "Hello"

# Generate and view documentation
just docs

# Clean build artifacts
just clean

Project Structure

PiSovereign/
β”œβ”€β”€ crates/                 # Rust crates
β”‚   β”œβ”€β”€ domain/            # Core business logic
β”‚   β”œβ”€β”€ application/       # Use cases, services
β”‚   β”œβ”€β”€ infrastructure/    # External adapters
β”‚   β”œβ”€β”€ ai_core/          # Inference engine
β”‚   β”œβ”€β”€ ai_speech/        # Speech processing
β”‚   β”œβ”€β”€ integration_*/    # Service integrations
β”‚   └── presentation_*/   # HTTP API, CLI
β”œβ”€β”€ docs/                  # mdBook documentation
β”œβ”€β”€ grafana/              # Monitoring configuration
β”œβ”€β”€ migrations/           # Database migrations
└── .github/              # CI/CD workflows

Adding a New Feature

  1. Domain layer (if new entities/values needed)

    # Edit crates/domain/src/entities/mod.rs
    # Add new entity module
    
  2. Application layer (service logic)

    # Add port trait in crates/application/src/ports/
    # Add service in crates/application/src/services/
    
  3. Infrastructure layer (adapters)

    # Implement port in crates/infrastructure/src/adapters/
    
  4. Presentation layer (API endpoints)

    # Add handler in crates/presentation_http/src/handlers/
    # Add route in crates/presentation_http/src/router.rs
    
  5. Tests

    # Unit tests alongside code
    # Integration tests in crates/*/tests/
    

Database Migrations

# Create new migration
cat > migrations/V007__my_migration.sql << 'EOF'
-- Description of migration
CREATE TABLE my_table (
    id TEXT PRIMARY KEY,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
EOF

# Migrations run automatically on startup (if enabled)
# Or manually:
pisovereign-cli migrate

Getting Help

Thank you for contributing! πŸŽ‰