# rcl-rlm

RLM (Recursive Language Model) for querying iMessage history. Uses iterative code execution to search and analyze your messages.

## How it works

1. You ask a question about your messages
2. LLM generates Python code to search the database
3. Code executes locally in a sandbox
4. LLM sees results and either answers or writes more code
5. Repeat until answer is found

This approach handles nuanced queries that keyword search can't:
- "What projects did we discuss?" (finds "initiative", "proposal", "idea")
- "When did I make dinner plans with John?" (reasons about context)
- "Who sends me the most messages on weekends?" (aggregates and analyzes)

## Setup

```bash
cd tools/rcl-rlm

# Create virtual environment
python3 -m venv .venv
source .venv/bin/activate

# Install dependencies
pip install -e .

# Set API key
export MODELRELAY_API_KEY=your_key_here
```

## Usage

```bash
# Basic query
rcl-rlm "What did John say about the project?"

# Verbose mode (shows code execution)
rcl-rlm "Find messages about dinner plans" --verbose

# Show full execution log
rcl-rlm "Who messages me the most?" --show-log

# Custom database path
rcl-rlm "Recent messages" --db /path/to/shadow.db
```

## Security

The code execution is sandboxed with multiple layers:

### 1. RestrictedPython (code-level)

Only safe operations are allowed:
- ✅ `sqlite3` queries (via `query()` function)
- ✅ `re` regex operations
- ✅ `json` parsing
- ✅ `collections.Counter`, `defaultdict`
- ✅ `datetime` operations
- ❌ File I/O (open, read, write)
- ❌ Network (socket, urllib, requests)
- ❌ Shell execution (subprocess, etc.)
- ❌ Dynamic imports

### 2. Read-only Database

Database is opened with `?mode=ro` - writes are impossible at SQLite level.

### 3. macOS sandbox-exec (OS-level, optional)

For additional isolation, run with macOS sandbox:

```bash
sandbox-exec -f sandbox.sb python3 -m rcl_rlm "query"
```

This restricts file access and blocks all network at the OS level.

## Architecture

```
User Question
     │
     ▼
┌─────────────────┐
│  ModelRelay API │  ◄── LLM reasoning (cloud)
└────────┬────────┘
         │ generates code
         ▼
┌─────────────────┐
│ RestrictedPython│  ◄── Code sandbox (local)
│    Sandbox      │
└────────┬────────┘
         │ query()
         ▼
┌─────────────────┐
│   shadow.db     │  ◄── Message data (local, read-only)
│   (SQLite)      │
└─────────────────┘
```

Data never leaves your device. Only the question and code outputs go to ModelRelay.

## Environment Variables

| Variable | Required | Description |
|----------|----------|-------------|
| `MODELRELAY_API_KEY` | Yes | Your ModelRelay API key |
| `SHADOW_DB_PATH` | No | Path to shadow.db (default: `~/Library/Application Support/RecallRLM/shadow.db`) |
| `RECALL_RLM_MODEL` | No | Override the default model (default: `gemini-3-flash-preview`) |
| `MODELRELAY_MODEL` | No | Alternate env var for model override |

## Comparison with SQL Agent

| Feature | SQL Agent | RLM |
|---------|-----------|-----|
| Approach | LLM generates SQL | LLM generates Python + SQL |
| Iterations | Single SQL query | Multiple code executions |
| Semantic queries | Limited (term expansion) | Strong (code-based reasoning) |
| Aggregation | SQL only | Python + SQL |
| Latency | ~14s | ~5-15s (depends on iterations) |

RLM is better for complex queries that require reasoning over results.
