Thanks for your interest in contributing to OxiBot! This document provides guidelines and instructions for contributing.
- Getting Started
- Development Setup
- Code Style
- Testing
- Pull Request Process
- Project Structure
- Adding a New Provider
- Adding a New Channel
- Adding a New Skill
- Commit Convention
- Fork the repository on GitHub
- Clone your fork locally
- Create a branch for your feature or fix
- Make changes following the guidelines below
- Submit a PR with a clear description
- Rust ≥ 1.84 (install via rustup)
- Node.js ≥ 20 (only for WhatsApp bridge development)
- cargo-watch (optional, for live reload):
cargo install cargo-watch
git clone https://github.com/DioCrafts/OxiBot.git
cd OxiBot
# Debug build (faster compilation)
cargo build --workspace
# Release build
cargo build --release --features "telegram,discord,whatsapp,slack,email"
# Watch mode (rebuild on changes)
cargo watch -x "build --workspace"cargo test --workspace
cargo test --workspace --features "telegram,discord,whatsapp,slack,email"We follow standard Rust conventions with a few project-specific guidelines.
# Format all code (required before PR)
cargo fmt --all
# Check formatting without modifying
cargo fmt --all -- --check# Run clippy (required: zero warnings)
cargo clippy --workspace --all-targets -- -D warnings
# With all features
cargo clippy --workspace --all-targets --features "telegram,discord,whatsapp,slack,email" -- -D warnings- Use
thiserrorfor error types, not manualimpl Display - Use
tracingfor logging, notprintln!oreprintln! - Async by default — use
tokiofor async runtime - Prefer
&stroverStringin function parameters when ownership isn't needed - Document public APIs — all
pubitems should have///doc comments - No
unwrap()in library code — use?or proper error handling unwrap()is OK in tests and in CLI entry points with clear error context
| Item | Convention | Example |
|---|---|---|
| Crates | oxibot-* kebab-case |
oxibot-core |
| Modules | snake_case |
agent_loop |
| Types/Traits | PascalCase |
AgentConfig |
| Functions | snake_case |
process_message |
| Constants | SCREAMING_SNAKE_CASE |
MAX_RETRIES |
| Feature flags | lowercase |
telegram, discord |
- Place unit tests in the same file, inside
#[cfg(test)] mod tests { ... } - Place integration tests in
tests/directory of the crate - Use
#[tokio::test]for async tests - Use
assert!,assert_eq!,assert_ne!— notunwrap()for assertions
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_defaults() {
let config = Config::default();
assert_eq!(config.gateway.port, 18790);
}
#[tokio::test]
async fn test_provider_sends_message() {
let provider = MockProvider::new();
let response = provider.chat("Hello").await.unwrap();
assert!(!response.is_empty());
}
}# Install cargo-tarpaulin (Linux only)
cargo install cargo-tarpaulin
# Run coverage
cargo tarpaulin --workspace --out Html- Code compiles:
cargo build --workspace - All tests pass:
cargo test --workspace - Code is formatted:
cargo fmt --all - No clippy warnings:
cargo clippy --workspace -- -D warnings - New code has tests
- Public APIs are documented
## What
Brief description of the change.
## Why
Motivation or issue reference.
## How
Technical approach taken.
## Testing
How this was tested.- Submit PR against
mainbranch - CI runs (build + test + clippy + fmt check)
- At least one maintainer review required
- Squash-merge when approved
crates/
├── oxibot-core/ # Config, event bus, session, heartbeat, types
├── oxibot-agent/ # Agent loop, tools, memory, context, skills
├── oxibot-providers/ # LLM provider backends (OpenAI, Anthropic, etc.)
├── oxibot-channels/ # Chat channel implementations
├── oxibot-cron/ # Scheduled task engine
└── oxibot-cli/ # CLI commands and gateway
cli → agent → providers
│ │
│ └──→ core
│ ↑
├──→ channels─┘
│
└──→ cron───→ core
Rules:
coredepends on nothing internal (only external crates)providersdepends oncoreagentdepends oncoreandproviderschannelsdepends oncorecrondepends oncoreclidepends on everything
- Create
crates/oxibot-providers/src/your_provider.rs - Implement the
LlmProvidertrait:
pub struct YourProvider {
client: reqwest::Client,
api_key: String,
api_base: String,
}
#[async_trait]
impl LlmProvider for YourProvider {
fn name(&self) -> &str { "your_provider" }
async fn chat(&self, request: &ChatRequest) -> Result<ChatResponse> {
// Implement API call
}
}- Register in
crates/oxibot-providers/src/lib.rs - Add config fields in
crates/oxibot-core/src/config.rs - Add tests
- Update README.md provider table
- Create
crates/oxibot-channels/src/your_channel.rs - Implement the
Channeltrait:
pub struct YourChannel { /* ... */ }
#[async_trait]
impl Channel for YourChannel {
fn name(&self) -> &str { "your_channel" }
async fn start(&self, bus: EventBus) -> Result<()> {
// Connect and start receiving messages
}
}- Add a feature flag in
crates/oxibot-channels/Cargo.toml:
[features]
your_channel = ["dep:your-channel-sdk"]- Gate the module with
#[cfg(feature = "your_channel")] - Register in CLI gateway startup
- Add config fields and tests
- Update README.md channel table
Skills are Markdown files in crates/oxibot-agent/skills/.
- Create
crates/oxibot-agent/skills/your-skill.md:
---
name: your-skill
description: Brief description of what this skill does
version: "1.0"
---
# Your Skill
Instructions for the agent on how to use this skill.
## When to activate
- User asks about X
- User wants to do Y
## How to respond
1. Step one
2. Step two
3. Step three- The skill is automatically loaded by the agent at startup
- Test by asking the agent something that should trigger the skill
We follow Conventional Commits:
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
| Type | Description |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation only |
style |
Formatting, no code change |
refactor |
Code change, no new feature or fix |
perf |
Performance improvement |
test |
Adding or fixing tests |
chore |
Build process, dependencies, CI |
core, agent, providers, channels, cron, cli, bridge, docker
feat(channels): add Matrix channel support
fix(agent): prevent infinite loop on empty response
docs(readme): add WhatsApp setup guide
test(providers): add unit tests for Groq provider
chore(docker): update base image to debian bookworm
Open a Discussion on GitHub or reach out to the maintainers.
Thank you for helping make OxiBot better! 🦀