Skip to main content
Thanks for your interest in contributing to RCLI. This guide covers the development workflow, testing, and how to submit changes.

Getting Started

Before making changes, ensure you can build and test RCLI locally.
1

Fork and clone

git clone https://github.com/YOUR_USERNAME/RCLI.git
cd RCLI
2

Set up dependencies

bash scripts/setup.sh              # Clone llama.cpp + sherpa-onnx
bash scripts/download_models.sh    # Download models (~1GB)
3

Build in debug mode

mkdir -p build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug
cmake --build . -j$(sysctl -n hw.ncpu)
4

Run tests

./rcli_test ~/Library/RCLI/models

Architecture Overview

Understanding the pipeline helps you identify where to make changes:
Mic → VAD → STT → [RAG] → LLM → TTS → Speaker
                            |
                     Tool Calling → macOS Actions

Threading Model

Three threads run concurrently in live mode:
  • Captures microphone audio via CoreAudio
  • Runs Silero VAD to filter silence
  • Detects speech endpoints
  • Feeds audio to Zipformer (streaming) or Whisper (batch)
  • Synchronizes via std::condition_variable
  • Waits for transcribed text from STT
  • Generates tokens via llama.cpp with Metal GPU
  • Dispatches tool calls when detected
  • Feeds sentences to TTS via SentenceDetector
  • Uses system prompt KV caching to avoid reprocessing
  • Queues sentences from LLM
  • Double-buffered playback (synthesizes next while playing current)
  • Uses sherpa-onnx (Piper/Kokoro/KittenTTS)
  • Outputs to CoreAudio speaker

Source Layout

src/
  engines/     ML engine wrappers (stt, llm, tts, vad, embedding)
  pipeline/    Orchestrator, sentence detector, text sanitizer
  rag/         Vector index, BM25, hybrid retriever, document processor
  core/        types.h, ring_buffer.h, memory_pool.h, hardware_profile.h
  audio/       CoreAudio mic/speaker I/O, WAV file I/O
  tools/       Tool calling engine with JSON schema definitions
  bench/       Benchmark harness (STT, LLM, TTS, E2E, RAG, memory)
  actions/     macOS action implementations (AppleScript + shell)
  api/         C API (rcli_api.h/.cpp) — the engine's public interface
  cli/         main.cpp, TUI dashboard (FTXUI), model pickers, help
  models/      Model registries (LLM, TTS, STT) with on-demand download
  test/        Pipeline test harness

Key Files

FilePurpose
src/api/rcli_api.hPublic C API — all engine functionality exposed here
src/pipeline/orchestrator.hCentral class that owns all engines and coordinates data flow
src/actions/action_registry.hAction registration and dispatch
src/models/model_registry.hLLM model definitions (id, URL, size, speed, flags)
src/models/tts_model_registry.hTTS voice definitions
src/models/stt_model_registry.hSTT model definitions
src/tools/tool_engine.hTool call parsing and execution

Testing

Test Executable

RCLI includes a test harness for verifying the pipeline:
cd build

# Run all tests
./rcli_test ~/Library/RCLI/models

# Fast action tests (no models needed)
./rcli_test ~/Library/RCLI/models --actions-only

# Component-specific tests
./rcli_test ~/Library/RCLI/models --llm-only
./rcli_test ~/Library/RCLI/models --stt-only
./rcli_test ~/Library/RCLI/models --tts-only
./rcli_test ~/Library/RCLI/models --api-only
The --actions-only suite runs without any model downloads and is a good smoke test for quick iteration.

Manual Testing

Test changes interactively:
./rcli
# Press SPACE to talk
# Press M for models panel
# Press A for actions panel
# Press B for benchmarks

Benchmarks

Run performance benchmarks:
./rcli bench                          # All benchmarks
./rcli bench --suite llm              # LLM only
./rcli bench --suite tools            # Tool calling
./rcli bench --all-llm --suite llm    # Compare all LLMs
./rcli bench --output results.json    # Export JSON
Suites: stt, llm, tts, e2e, tools, rag, memory, all

Code Style

Follow these conventions when contributing:

Language and Standards

  • C++17 with Apple Clang
  • No external package manager — all dependencies vendored or CMake-fetched
  • Header-only where practical for CLI modules (reduces build complexity)

Output and Formatting

  • Avoid emojis in output strings — use plain text markers ([ok], [PASS], >, *, Tip:)
  • Use fprintf(stderr, ...) for user-facing output
  • Stdout is reserved for machine-parseable output (JSON, etc.)

Memory Management

  • Pre-allocated memory pool (64 MB arena) — avoid runtime malloc during inference
  • Lock-free ring buffers for zero-copy audio transfer
  • RAII for resource management

Design Patterns

  • Orchestrator pattern — central class owns all engines
  • Atomic pipeline statestd::atomic<PipelineState>
  • Sentence-level TTS scheduling — flush complete sentences only
  • System prompt KV caching — reuse llama.cpp state across queries

Good First Issues

Looking for a place to start? Try these:

Add a macOS action

Implement a new action like send_email or create_calendar_event. See Adding Actions.

Add an LLM model

Register a new GGUF model in src/models/model_registry.h.

Improve error messages

Make error messages more actionable and user-friendly.

Add a benchmark

Extend the benchmark suite in src/bench/benchmark.cpp.

Pull Request Process

1

Create a feature branch

git checkout -b feature/my-change
2

Make your changes

  • Write code following the style guide
  • Add tests if applicable
  • Ensure the build succeeds:
    cd build
    cmake --build . -j$(sysctl -n hw.ncpu)
    
3

Run tests

./rcli_test ~/Library/RCLI/models
If your changes affect the engine, ensure all tests pass.
4

Commit with clear messages

git add .
git commit -m "Add: Spotify pause action"
Commit message format:
  • Add: for new features
  • Fix: for bug fixes
  • Update: for enhancements
  • Refactor: for code restructuring
5

Push and open a PR

git push origin feature/my-change
Open a pull request on GitHub with:
  • Clear description of what changed and why
  • Screenshots/videos for UI changes
  • Test results if applicable

Extension Points

Common contribution areas:

Adding Actions

See the dedicated Adding Actions guide.

Adding Models

Edit src/models/model_registry.h and add to all_models():
{
    /* id            */ "my-model-id",
    /* name          */ "My Model Name",
    /* filename      */ "my-model.gguf",
    /* url           */ "https://huggingface.co/.../my-model.gguf",
    /* family        */ "model-family",
    /* size_mb       */ 500,
    /* priority      */ 10,
    /* speed_est     */ "~200 t/s",
    /* tool_calling  */ "Good",
    /* description   */ "Brief description.",
    /* is_default    */ false,
    /* is_recommended*/ false,
}
Edit src/models/tts_model_registry.h and add to all_tts_models():
  • architecture — sherpa-onnx backend (vits, kokoro, matcha, kitten)
  • dir_name — subdirectory under ~/Library/RCLI/models/
  • download_url — URL to .tar.bz2 archive
Edit src/models/stt_model_registry.h:
  • streaming — for live mic (e.g., Zipformer)
  • offline — for batch transcription (e.g., Whisper, Parakeet)

Resources

GitHub Issues

Report bugs and request features

Project Structure

Understand the codebase layout

Building from Source

Build and install RCLI locally

Build docs developers (and LLMs) love