Keyboard shortcuts

Press ← or β†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Code Style

🎨 Coding standards and style guidelines for ReasonKit contributors.

ReasonKit is written in Rust and follows strict code quality standards. This guide helps you write code that fits seamlessly into the codebase.

Core Philosophy

  1. Clarity over cleverness β€” Readable code wins
  2. Explicit over implicit β€” Don’t hide behavior
  3. Fail fast, fail loud β€” No silent failures
  4. Performance matters β€” But not at the cost of correctness

Rust Style Guide

Formatting

We use rustfmt with project-specific settings. Always run before committing:

cargo fmt

Configuration (.rustfmt.toml):

edition = "2021"
max_width = 100
tab_spaces = 4
use_small_heuristics = "Default"

Naming Conventions

ItemConventionExample
Types/TraitsPascalCaseThinkTool, ReasoningProfile
Functions/Methodssnake_caserun_analysis(), get_config()
Variablessnake_caseuser_input, analysis_result
ConstantsSCREAMING_SNAKEDEFAULT_TIMEOUT, MAX_RETRIES
Modulessnake_casethinktool, retrieval
Feature flagskebab-caseembeddings-local

Error Handling

Use the crate’s error types consistently:

#![allow(unused)]
fn main() {
use crate::error::{ReasonKitError, Result};

// Good: Use ? operator with context
fn process_input(input: &str) -> Result<Analysis> {
    let parsed = parse_input(input)
        .map_err(|e| ReasonKitError::Parse(format!("Invalid input: {}", e)))?;

    analyze(parsed)
}

// Bad: Unwrap in library code
fn process_input_bad(input: &str) -> Analysis {
    parse_input(input).unwrap()  // Don't do this!
}
}

Documentation

Every public item must have documentation:

#![allow(unused)]
fn main() {
/// Executes the GigaThink reasoning module.
///
/// Generates multiple perspectives on a problem by exploring
/// it from different viewpoints, stakeholders, and frames.
///
/// # Arguments
///
/// * `input` - The question or problem to analyze
/// * `config` - GigaThink configuration options
///
/// # Returns
///
/// A `GigaThinkResult` containing all generated perspectives
/// and a synthesis of the analysis.
///
/// # Errors
///
/// Returns `ReasonKitError::Provider` if the LLM call fails.
///
/// # Example
///
/// ```rust
/// use reasonkit::thinktool::{gigathink, GigaThinkConfig};
///
/// let config = GigaThinkConfig::default();
/// let result = gigathink("Should I switch jobs?", &config)?;
/// println!("Found {} perspectives", result.perspectives.len());
/// ```
pub fn gigathink(input: &str, config: &GigaThinkConfig) -> Result<GigaThinkResult> {
    // implementation
}
}

Module Organization

#![allow(unused)]
fn main() {
// mod.rs structure
//
// 1. Module documentation
// 2. Re-exports (pub use)
// 3. Public types
// 4. Private types
// 5. Public functions
// 6. Private functions
// 7. Tests

//! ThinkTool execution module.
//!
//! This module provides the core reasoning tools that power ReasonKit.

pub use self::executor::Executor;
pub use self::profiles::{Profile, ProfileConfig};

mod executor;
mod profiles;
mod registry;

/// Main entry point for ThinkTool execution.
pub fn run(input: &str, profile: &Profile) -> Result<Analysis> {
    let executor = Executor::new(profile)?;
    executor.run(input)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_run_with_default_profile() {
        // test implementation
    }
}
}

Imports

Organize imports in this order:

#![allow(unused)]
fn main() {
// 1. Standard library
use std::collections::HashMap;
use std::path::PathBuf;

// 2. External crates
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc;

// 3. Internal crates (workspace members)
use reasonkit_db::VectorStore;

// 4. Crate modules
use crate::error::Result;
use crate::thinktool::Profile;

// 5. Super/self
use super::Config;
}

Async Code

ReasonKit uses Tokio for async operations:

#![allow(unused)]
fn main() {
// Good: Use async properly
pub async fn call_llm(prompt: &str) -> Result<String> {
    let client = Client::new();
    let response = client
        .post(&api_url)
        .json(&request)
        .send()
        .await
        .map_err(|e| ReasonKitError::Provider(e.to_string()))?;

    response.text().await
        .map_err(|e| ReasonKitError::Parse(e.to_string()))
}

// Good: Spawn tasks when parallelism helps
pub async fn run_tools_parallel(
    input: &str,
    tools: &[Tool],
) -> Result<Vec<ToolResult>> {
    let handles: Vec<_> = tools
        .iter()
        .map(|tool| {
            let input = input.to_string();
            let tool = tool.clone();
            tokio::spawn(async move { tool.run(&input).await })
        })
        .collect();

    futures::future::try_join_all(handles)
        .await
        .map_err(|e| ReasonKitError::Internal(e.to_string()))
}
}

Linting

All code must pass Clippy with no warnings:

cargo clippy -- -D warnings

Common Clippy fixes:

#![allow(unused)]
fn main() {
// Bad: Unnecessary clone
let s = some_string.clone();
do_something(&s);

// Good: Borrow instead
do_something(&some_string);

// Bad: Redundant pattern matching
match result {
    Ok(v) => Some(v),
    Err(_) => None,
}

// Good: Use .ok()
result.ok()
}

Performance Guidelines

Avoid Allocations in Hot Paths

#![allow(unused)]
fn main() {
// Bad: Allocates on every call
fn format_error(code: u32) -> String {
    format!("Error code: {}", code)
}

// Good: Return static str when possible
fn error_message(code: u32) -> &'static str {
    match code {
        1 => "Invalid input",
        2 => "Timeout",
        _ => "Unknown error",
    }
}
}

Use Iterators Over Vectors

#![allow(unused)]
fn main() {
// Bad: Creates intermediate vector
let results: Vec<_> = items.iter()
    .filter(|x| x.is_valid())
    .collect();
let sum: u32 = results.iter().map(|x| x.value).sum();

// Good: Chain iterator operations
let sum: u32 = items.iter()
    .filter(|x| x.is_valid())
    .map(|x| x.value)
    .sum();
}

Testing Requirements

See Testing Guide for full details. Quick summary:

  • Unit tests for all public functions
  • Integration tests for cross-module behavior
  • Benchmarks for performance-critical code

Pre-Commit Checklist

Before every commit:

# Format code
cargo fmt

# Run linter
cargo clippy -- -D warnings

# Run tests
cargo test

# Check docs compile
cargo doc --no-deps