Skip to main content

Overview

RCLI provides 43+ macOS actions for system control and automation:
  • Apps: Open, quit, switch apps
  • System: Volume, brightness, clipboard, screenshots
  • Calendar: Create events, list upcoming meetings
  • Reminders: Create, list, complete tasks
  • Notes: Create, search, append notes
  • Music: Play, pause, next/previous track
  • Contacts: Search, get details
  • Files: Open, move, delete files
  • Network: Check Wi-Fi, speed test
  • Time: Current time, timezone info
  • Calculation: Math expressions
Actions are implemented via AppleScript and shell commands, registered as LLM tools.

Action Execution

rcli_action_execute

Execute a named action with JSON arguments.
const char* rcli_action_execute(
    RCLIHandle handle,
    const char* action_name,
    const char* args_json
);
handle
RCLIHandle
required
Engine handle (must be initialized)
action_name
const char*
required
Action name (e.g., "open_app", "create_reminder", "set_volume")
args_json
const char*
required
JSON arguments for the action. Format varies per action.Example:
{"app": "Safari"}
return
const char*
JSON result:
{"success": true, "output": "Opened Safari", "error": ""}
Do not free - owned by the engine.

Example: Open an App

const char* result = rcli_action_execute(
    handle,
    "open_app",
    "{\"app\": \"Safari\"}"
);

printf("%s\n", result);
// {"success":true,"output":"Opened Safari","error":""}

Example: Set Volume

const char* result = rcli_action_execute(
    handle,
    "set_volume",
    "{\"level\": 50}"
);

printf("%s\n", result);
// {"success":true,"output":"Volume set to 50%","error":""}

Example: Create Reminder

const char* result = rcli_action_execute(
    handle,
    "create_reminder",
    "{\"title\": \"Buy milk\", \"list\": \"Shopping\"}"
);

printf("%s\n", result);
// {"success":true,"output":"Created reminder: Buy milk","error":""}
Actions execute synchronously and may take 100-500ms (AppleScript overhead). Use callbacks for non-blocking notification.

Action Discovery

rcli_action_list

List all available actions (returns JSON array).
const char* rcli_action_list(RCLIHandle handle);
handle
RCLIHandle
required
Engine handle
return
const char*
JSON array of action definitions. Do not free.Example:
[
  {
    "name": "open_app",
    "description": "Open a macOS application",
    "parameters": {"type": "object", "properties": {...}},
    "category": "apps",
    "enabled": true
  },
  ...
]

Example: Print All Actions

const char* actions = rcli_action_list(handle);
printf("%s\n", actions);

Common Actions

ActionDescriptionArguments
open_appOpen application{"app": "Safari"}
quit_appQuit application{"app": "Safari"}
set_volumeSet system volume{"level": 50} (0-100)
set_brightnessSet screen brightness{"level": 75} (0-100)
create_reminderCreate reminder{"title": "Task", "list": "Work"}
create_noteCreate note{"title": "Note", "body": "Content"}
create_eventCreate calendar event{"title": "Meeting", "date": "2025-03-15", "time": "2:00 PM"}
take_screenshotTake screenshot{"path": "/tmp/shot.png"}
get_clipboardGet clipboard text{}
set_clipboardSet clipboard text{"text": "Hello"}
play_musicPlay music{}
pause_musicPause music{}
get_current_timeGet current time{}
calculateEvaluate math{"expression": "2 + 2"}

Action Visibility (Enable/Disable)

Control which actions the LLM can see and call.

rcli_set_action_enabled

Enable or disable an action for LLM visibility.
int rcli_set_action_enabled(
    RCLIHandle handle,
    const char* name,
    int enabled
);
handle
RCLIHandle
required
Engine handle
name
const char*
required
Action name
enabled
int
required
  • 1: Enable (LLM can call this action)
  • 0: Disable (hide from LLM)
return
int
  • 0: Success
  • -1: Action not found

Example: Disable Sensitive Actions

// Disable file deletion
rcli_set_action_enabled(handle, "delete_file", 0);

// Disable quit app
rcli_set_action_enabled(handle, "quit_app", 0);

// Re-sync tool definitions with LLM
// (happens automatically)
Changing action visibility invalidates the LLM’s KV cache and rebuilds the system prompt with updated tool definitions.

rcli_is_action_enabled

Check if an action is currently enabled.
int rcli_is_action_enabled(RCLIHandle handle, const char* name);
handle
RCLIHandle
required
Engine handle
name
const char*
required
Action name
return
int
  • 1: Action is enabled
  • 0: Action is disabled or doesn’t exist

Example: Check Status

if (rcli_is_action_enabled(handle, "delete_file")) {
    printf("File deletion is enabled\n");
} else {
    printf("File deletion is disabled\n");
}

Action Preferences

rcli_save_action_preferences

Persist action enable/disable state to ~/.rcli/actions.json.
int rcli_save_action_preferences(RCLIHandle handle);
handle
RCLIHandle
required
Engine handle
return
int
  • 0: Saved successfully
  • -1: Failed (disk error, permission denied)

Example: Save User Preferences

// User customizes actions
rcli_set_action_enabled(handle, "delete_file", 0);
rcli_set_action_enabled(handle, "quit_app", 0);
rcli_set_action_enabled(handle, "create_reminder", 1);

// Persist to disk
if (rcli_save_action_preferences(handle) == 0) {
    printf("Preferences saved\n");
}

// Next launch: preferences auto-load from ~/.rcli/actions.json

Preferences File Format

~/.rcli/actions.json:
{
  "enabled": [
    "open_app",
    "create_reminder",
    "set_volume",
    "get_current_time"
  ],
  "disabled": [
    "delete_file",
    "quit_app"
  ]
}
Preferences are auto-loaded during rcli_init(). No manual loading required.

LLM Tool Calling

Actions are automatically registered as LLM tools. The LLM decides when to call them based on user input.

Example: Voice Command → Action

void on_action(const char* name, const char* result, int success, void* user_data) {
    printf("Action: %s -> %s\n", name, success ? "OK" : "FAILED");
}

rcli_set_action_callback(handle, on_action, NULL);

// User says: "Open Safari"
rcli_process_command(handle, "open Safari");

// LLM detects tool call: open_app({"app": "Safari"})
// Callback fires: on_action("open_app", "{...}", 1, NULL)
// User hears: "Opened Safari"

Tool Call Flow

  1. User input: "open Safari"
  2. LLM receives system prompt with tool definitions
  3. LLM emits tool call: <tool_call>{"name": "open_app", "arguments": {"app": "Safari"}}</tool_call>
  4. Tool engine parses and executes action
  5. Action result summarized: "Opened Safari"
  6. TTS speaks response

Tool Filtering (Optimization)

To avoid overwhelming small LLMs, the engine filters tools by relevance:
  • Keyword overlap: Score actions by query relevance
  • Top-10: Include only the most relevant actions
  • Built-in tools: Always include get_current_time, calculate
Example: Query "remind me to buy milk"
  • Relevant: create_reminder, list_reminders
  • Irrelevant: set_brightness, take_screenshot (filtered out)

Model Hot-Swap

rcli_switch_llm

Switch the active LLM model at runtime without restarting.
int rcli_switch_llm(RCLIHandle handle, const char* model_id);
handle
RCLIHandle
required
Engine handle (must be initialized)
model_id
const char*
required
Model ID from registry (e.g., "qwen3-0.6b", "lfm2-1.2b", "qwen3.5-2b")
return
int
  • 0: Model switched successfully
  • -1: Failed (model not found, out of memory)

Example: Switch to Larger Model

// Start with default (Qwen3 0.6B)
rcli_init(handle, "/path/to/models", 99);

rcli_process_command(handle, "Hello");
// Using Qwen3 0.6B

// Switch to larger model
if (rcli_switch_llm(handle, "qwen3.5-2b") == 0) {
    printf("Switched to Qwen3.5 2B\n");
}

rcli_process_command(handle, "Explain quantum computing");
// Now using Qwen3.5 2B (better reasoning)
Model switching:
  • Unloads current model (frees VRAM)
  • Loads new model (~2-5 seconds)
  • Invalidates conversation history
  • Rebuilds system prompt with correct tool-calling format

Complete Example: Action Manager

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

void on_action(const char* name, const char* result, int success, void* user_data) {
    if (success) {
        printf("\u2713 %s completed\n", name);
    } else {
        printf("\u2717 %s failed\n", name);
    }
}

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

    // Register callback
    rcli_set_action_callback(handle, on_action, NULL);

    // List all actions
    const char* actions = rcli_action_list(handle);
    printf("Available actions:\n%s\n\n", actions);

    // Execute actions directly
    printf("Opening Safari...\n");
    rcli_action_execute(handle, "open_app", "{\"app\": \"Safari\"}");

    printf("Setting volume to 50%%...\n");
    rcli_action_execute(handle, "set_volume", "{\"level\": 50}");

    // LLM-driven execution
    printf("\nVoice command: 'create a reminder to buy milk'\n");
    const char* response = rcli_process_command(handle, "create a reminder to buy milk");
    printf("Response: %s\n", response);

    // Disable sensitive actions
    printf("\nDisabling file deletion...\n");
    rcli_set_action_enabled(handle, "delete_file", 0);
    rcli_save_action_preferences(handle);

    rcli_destroy(handle);
    return 0;
}

See Also

Build docs developers (and LLMs) love