Skip to main content

Overview

RCLI provides 43 macOS actions that allow you to control your Mac using voice or text. The LLM automatically routes your intent to the appropriate action, executes it via AppleScript or shell commands, and returns the result.

Voice-Activated

Speak naturally - the LLM understands intent

Text Commands

Use rcli ask "<command>" for scripting

Tool Calling

LLM-native tool formats (Qwen3, LFM2)

Enable/Disable

Customize which actions are available

Action Categories

Productivity

ActionDescriptionExample
create_noteCreate a note in Apple Notes”Create a note called Meeting Notes”
create_reminderCreate a reminder with due date”Remind me to call John tomorrow”
run_shortcutExecute Apple Shortcuts”Run my morning routine shortcut”

Communication

ActionDescriptionExample
send_messageSend iMessage or SMS”Send a message to Alice saying I’m running late”
facetime_callStart FaceTime video call”FaceTime Bob”
facetime_audioStart FaceTime audio call”Call Mom on FaceTime audio”

Media

ActionDescriptionExample
play_on_spotifySearch and play on Spotify”Play some jazz on Spotify”
play_apple_musicPlay from Apple Music library”Play my workout playlist”
play_pause_musicToggle play/pause”Pause the music”
next_trackSkip to next track”Next song”
previous_trackGo to previous track”Previous track”
set_music_volumeAdjust music volume”Set music volume to 50”
get_now_playingGet current track info”What’s playing?”

System

ActionDescriptionExample
open_appLaunch an application”Open Safari”
quit_appQuit an application”Quit Chrome”
set_volumeSet system volume”Set volume to 75”
toggle_dark_modeSwitch light/dark mode”Turn on dark mode”
lock_screenLock the Mac”Lock my computer”
screenshotCapture screenshot”Take a screenshot”
search_filesSearch files with Spotlight”Find my tax documents”
open_settingsOpen System Settings”Open settings”
open_urlOpen URL in browser”Open github.com”
get_batteryGet battery status”What’s my battery level?”
get_wifiGet WiFi network name”What WiFi am I connected to?”
get_ip_addressGet IP address”What’s my IP address?”
get_uptimeGet system uptime”How long has my Mac been running?”
get_disk_usageGet disk space info”How much disk space do I have?”

Window Management

ActionDescriptionExample
close_windowClose active window”Close this window”
minimize_windowMinimize active window”Minimize the window”
fullscreen_windowToggle fullscreen”Make this fullscreen”
get_frontmost_appGet active app name”What app is open?”
list_appsList running apps”What apps are running?”

Web & Navigation

ActionDescriptionExample
search_webGoogle search”Search for Apple Silicon benchmarks”
search_youtubeYouTube search”Find videos about Qwen3”
get_browser_urlGet active tab URL”What URL am I on?”
get_browser_tabsList all open tabs”What tabs do I have open?”
open_mapsOpen Apple Maps”Navigate to the Golden Gate Bridge”

Clipboard

ActionDescriptionExample
clipboard_readGet clipboard content”What’s in my clipboard?”
clipboard_writeSet clipboard content”Copy ‘Hello World’ to clipboard”

Tool Calling Architecture

RCLI uses LLM-native tool calling with model-specific formats:
1

User Input

Voice or text command: “Open Safari”
2

STT Transcription

Speech converted to text via Zipformer/Whisper
3

LLM Processing

LLM receives prompt with tool definitions and user query
4

Tool Call Generation

LLM outputs structured tool call:
<tool_call>
{"name": "open_app", "arguments": {"app_name": "Safari"}}
</tool_call>
5

Action Execution

Tool engine dispatches to action handler:
// From src/actions/app_control_actions.cpp:15-45
ActionResult open_app(const std::string& args) {
    // Parse JSON args
    // Execute AppleScript
    return {success: true, output: "Opened Safari"};
}
6

Result to LLM

Execution result fed back to LLM:
{"success": true, "output": "Opened Safari"}
7

Natural Response

LLM generates friendly response: “Done! Safari is now open.”
8

TTS Output

Response synthesized and played via Piper/Kokoro

AppleScript Executor

Most actions are implemented using AppleScript for macOS automation:
// From src/actions/applescript_executor.cpp:20-75
ActionResult execute_applescript(const std::string& script) {
    // Escape script for shell
    std::string cmd = "osascript -e " + shell_quote(script);
    
    // Execute with popen
    FILE* pipe = popen(cmd.c_str(), "r");
    
    // Read output
    std::string output;
    char buffer[1024];
    while (fgets(buffer, sizeof(buffer), pipe)) {
        output += buffer;
    }
    
    int exit_code = pclose(pipe);
    return {exit_code == 0, output};
}
All AppleScript is executed synchronously with a 10-second timeout to prevent hanging.

Example: create_note Action

// From src/actions/notes_actions.cpp:12-45
ActionResult create_note(const std::string& args) {
    // Parse JSON: {"title": "...", "body": "..."}
    std::string title, body;
    parse_json_args(args, title, body);
    
    // Build AppleScript
    std::string script = R"(
        tell application "Notes"
            make new note with properties {name:"" + title + "", body:"" + body + ""}
        end tell
    )";
    
    // Execute
    auto result = execute_applescript(script);
    
    if (result.success) {
        return {true, "Created note: " + title};
    } else {
        // Fallback: use 'memo' CLI if AppleScript fails
        std::string cmd = "echo '" + body + "' > ~/Notes/" + title + ".txt";
        system(cmd.c_str());
        return {true, "Created text file: " + title};
    }
}

Managing Actions

Enable/Disable Actions

You can control which actions are available to the LLM:
Press A in the TUI to open the Actions panel:
  • Arrow Keys: Navigate actions
  • SPACE: Toggle enable/disable
  • ENTER: Execute action directly
  • ESC: Close panel
Changes are persisted to ~/Library/RCLI/config/actions.json.

Tool Definition Filtering

For small LLMs (< 2B params), RCLI uses top-k relevance scoring to filter tool definitions:
// From src/tools/tool_engine.cpp:145-200
std::string ToolEngine::get_filtered_tools(const std::string& query, int k) {
    // Score each tool by keyword match
    std::vector<std::pair<int, std::string>> scored_tools;
    for (const auto& tool : all_tools_) {
        int score = compute_relevance(query, tool.keywords);
        scored_tools.push_back({score, tool.name});
    }
    
    // Sort and take top-k
    std::sort(scored_tools.rbegin(), scored_tools.rend());
    return build_tool_json(scored_tools, k);
}
This reduces context overhead from ~12K tokens (all 43 tools) to ~2K tokens (top 7 tools).

Tool Call Trace

Press T in the TUI to enable tool call tracing. Every tool call and result will be displayed inline:
> open Safari
  ~ [TRACE] Tool call: open_app({"app_name": "Safari"})
  ~ [TRACE] open_app -> OK: {"success": true, "output": "Opened Safari"}
  RCLI: Done! Safari is now open.
Use rcli bench --suite tools to benchmark tool-calling accuracy:
rcli bench --suite tools
rcli bench --all-llm --suite tools  # Compare across models

Safety Considerations

Communication Actions: Actions like send_message and facetime_call have no confirmation prompt. The LLM will execute them immediately. To prevent accidental messages, disable these actions when not needed.
Recommended Practice: Keep sensitive actions (messages, shortcuts) disabled by default. Enable them temporarily when needed, then disable again.

Next Steps

Action Details

See complete action reference with parameters

Adding Actions

Learn how to implement custom actions

Voice Pipeline

Understand the STT → LLM → TTS flow

Commands

Explore all RCLI commands

Build docs developers (and LLMs) love