Skip to main content

Overview

The RCLI engine follows a simple lifecycle: create → initialize → use → destroy.
RCLIHandle handle = rcli_create(config_json);
rcli_init(handle, models_dir, gpu_layers);
// ... use the API ...
rcli_destroy(handle);

rcli_create

Create a RCLI engine instance.
RCLIHandle rcli_create(const char* config_json);
config_json
const char*
Optional JSON configuration string. Pass NULL for defaults.Supported keys:
  • system_prompt (string): Custom LLM system prompt
  • gpu_layers (int): GPU layer count override
  • ctx_size (int): LLM context window size
return
RCLIHandle
Opaque handle to the engine instance, or NULL on failure (out of memory).

Example

// Default configuration
RCLIHandle handle = rcli_create(NULL);
if (!handle) {
    fprintf(stderr, "Failed to create engine\n");
    return -1;
}
// Custom configuration
const char* config = 
    "{"
    "  \"system_prompt\": \"You are RCLI, a macOS voice assistant.\","
    "  \"gpu_layers\": 99,"
    "  \"ctx_size\": 8192"
    "}";

RCLIHandle handle = rcli_create(config);
rcli_create() allocates memory but does not load models. Call rcli_init() to complete initialization.

rcli_init

Initialize all engines (STT, LLM, TTS, VAD, Actions).
int rcli_init(RCLIHandle handle, const char* models_dir, int gpu_layers);
handle
RCLIHandle
required
Engine handle from rcli_create()
models_dir
const char*
required
Path to directory containing model files. Must include:
  • zipformer/ (streaming STT)
  • whisper-base.en/ or parakeet-tdt-* (offline STT)
  • LLM GGUF file (e.g., qwen3-0.6b-q4_k_m.gguf)
  • piper-voice/ or kokoro/ (TTS)
  • silero_vad.onnx
  • espeak-ng-data/
gpu_layers
int
required
Number of LLM layers to offload to GPU:
  • 99: All layers (recommended for Apple Silicon)
  • 0: CPU-only mode
  • 1-50: Partial GPU offload
return
int
  • 0: Success
  • Non-zero: Initialization failed (missing models, invalid paths, etc.)

Example

RCLIHandle handle = rcli_create(NULL);

if (rcli_init(handle, "/Users/me/models", 99) != 0) {
    fprintf(stderr, "Initialization failed\n");
    rcli_destroy(handle);
    return -1;
}

printf("Engine ready\n");
Initialization can take 2-5 seconds. Model loading happens on the calling thread.

Model Detection

The engine automatically selects models based on priority:
  1. LLM: Scans for GGUF files, selects highest-priority model (Qwen3 > LFM2 > others)
  2. STT: Prefers Parakeet TDT (high-accuracy) over Whisper if available
  3. TTS: Selects best available voice (Kokoro > KittenTTS > Piper)
You can override model selection via user preferences in ~/.rcli/config.json.

rcli_is_ready

Check if the engine is initialized and ready to use.
int rcli_is_ready(RCLIHandle handle);
handle
RCLIHandle
required
Engine handle
return
int
  • 1: Engine is initialized
  • 0: Not initialized or invalid handle

Example

if (!rcli_is_ready(handle)) {
    fprintf(stderr, "Engine not ready - call rcli_init() first\n");
    return -1;
}

rcli_start_listening(handle);

rcli_destroy

Destroy the engine and free all resources.
void rcli_destroy(RCLIHandle handle);
handle
RCLIHandle
required
Engine handle to destroy. Safe to pass NULL.

Example

RCLIHandle handle = rcli_create(NULL);
rcli_init(handle, "/path/to/models", 99);

// ... use the API ...

// Clean up
rcli_destroy(handle);
handle = NULL;  // Good practice
  • Always call rcli_destroy() before your program exits
  • Do not use the handle after calling rcli_destroy()
  • Safe to call even if rcli_init() failed
  • Automatically stops any running voice pipeline

Complete Example

#include "api/rcli_api.h"
#include <stdio.h>

int main() {
    // 1. Create
    RCLIHandle handle = rcli_create(NULL);
    if (!handle) {
        fprintf(stderr, "Failed to create engine\n");
        return 1;
    }

    // 2. Initialize
    const char* models = "/Users/me/Library/RCLI/models";
    if (rcli_init(handle, models, 99) != 0) {
        fprintf(stderr, "Initialization failed\n");
        rcli_destroy(handle);
        return 1;
    }

    // 3. Verify ready
    if (!rcli_is_ready(handle)) {
        fprintf(stderr, "Engine not ready\n");
        rcli_destroy(handle);
        return 1;
    }

    // 4. Use the API
    const char* response = rcli_process_command(handle, "What time is it?");
    printf("Response: %s\n", response);

    // 5. Destroy
    rcli_destroy(handle);
    return 0;
}

Error Handling

RCLIHandle handle = rcli_create(NULL);
if (!handle) {
    // Out of memory - very rare
    return -1;
}

int result = rcli_init(handle, models_dir, 99);
if (result != 0) {
    // Common causes:
    // - models_dir doesn't exist
    // - Required model files missing
    // - Insufficient GPU memory
    // - Incompatible model format
    
    fprintf(stderr, "Init failed with code: %d\n", result);
    rcli_destroy(handle);
    return -1;
}

See Also

Build docs developers (and LLMs) love