Documentation
The Ren manual
Everything needed to get Ren — your private, local-first assistant powered by Claude — installed, configured, and talking to your home. Every command, path and setting below is taken straight from the codebase.
On this page
Before you start
Requirements
Ren is a small FastAPI service that wraps Claude with on-device memory, a tool plugin layer and a stable cryptographic identity. It runs comfortably on hardware you already own.
- Python 3.12+ — tested on Apple Silicon Macs and Linux x86-64 (NUC-class hardware).
- No GPU. All language inference goes to the Anthropic API. The optional voice stack runs on CPU.
- An Anthropic API key for chat. Local features (memory, threads, home polling) work without one.
uvfor dependency management, or Docker if you prefer the container path.
Setup
Install
Ren uses uv for a fast, reproducible virtualenv. If you do not have it yet:
curl -LsSf https://astral.sh/uv/install.sh | sh
Then, from the repo root, three commands get you running:
make install # uv sync --extra dev — creates .venv, installs deps cp .env.example .env # then add your ANTHROPIC_API_KEY make run # serves on http://127.0.0.1:8000
make test, make lint, and make eval all run without a key.Setup
Configure
Ren reads settings from environment variables or a local .env file. Copy .env.example to .env and set at least your key:
ANTHROPIC_API_KEY=sk-ant-...
.env. It is gitignored — your key and tokens live only on the machine running Ren.Core
| Variable | Default | What it does |
|---|---|---|
ANTHROPIC_API_KEY | — | Your Claude API key (read without the REN_ prefix, the same name the SDK uses). Required for /chat — the server still boots without it. |
REN_DEFAULT_TIER | default | Model tier when a request does not specify one: fast | default | hard. |
REN_HOST | 127.0.0.1 | Bind address. Stays loopback-only unless you change it. |
REN_PORT | 8000 | TCP port the API and web client listen on. |
REN_DB_PATH | ./data/ren.db | On-device SQLite file holding all memory, threads and reminders. Gitignored, never synced. |
REN_CHAT_TIMEOUT_S | 60 | Maximum seconds a /chat call may run before returning 504. |
Files & safety
| Variable | Default | What it does |
|---|---|---|
REN_FILES_ROOT | ./data/files | Sandbox root for the file tools. Any path traversal outside it is refused. |
REN_ALLOW_DANGEROUS_TOOLS | false | Side-effecting tools (write, delete, export, device control) are gated off by default. Set true to unlock them globally — or enable per-thread. |
REN_IDENTITY_ROOT | file | Provenance of the identity key: file (PEM on disk) | mock (in-memory) | hardware (sovereign SE, later). |
REN_ALLOW_DANGEROUS_TOOLS=false (the default), Ren explains what it wanted to do instead of acting blind. Unlock side effects per-thread with a PATCH /threads/{id} carrying { "allow_dangerous": true } — or globally with the env var.Persona
| Variable | Default | What it does |
|---|---|---|
REN_PERSONA_NAME | Ren | What the assistant calls itself. |
REN_PERSONA_INSTRUCTIONS | — | Free-text personality overlay, e.g. "You answer concisely and dryly." |
REN_PERSONA_FILE | — | Path to a text file read as the persona overlay instead of inline instructions. |
Voice
Off by default and fully opt-in — see Voice setup below for the full walkthrough.
| Variable | Default | What it does |
|---|---|---|
REN_VOICE_ENABLED | false | Master switch. Off by default — the ML stack loads only when this is true. |
REN_VOICE_WAKE_ENABLED | false | Continuous wake-word listening. When off, audio is processed only after you start a session. |
REN_VOICE_STT_MODEL | tiny | Whisper model size for speech-to-text (CPU-only). |
REN_VOICE_TTS_VOICE | en_US-lessac-medium | Piper voice used for text-to-speech. |
REN_VOICE_VAD_THRESHOLD | 0.5 | Silero voice-activity-detection sensitivity (0–1). |
Home & connectors
Start with the provider switch REN_HOME_PROVIDER ("" off, homeassistant, or webhook). On top of that, Ren ships 18+ direct connectors — Hue, HomeKit, Matter, Z-Wave, Sonos, Roku, SmartThings, EVs and more — each with its own REN_* variables. Rather than reproduce all forty here, the full per-connector table lives on the API page.
WREN_* variable names are still honored as aliases (Ren logs a one-time deprecation warning). An explicit REN_* always wins.Operate
Run
Start the server, then confirm it is alive. /health always responds and reports whether an API key is configured:
make run # http://127.0.0.1:8000
curl -s localhost:8000/health # {"status":"ok","version":"1.0.0","has_api_key":true}Talk to Ren over HTTP, or stream tokens over SSE:
curl -s localhost:8000/chat -H 'content-type: application/json' \
-d '{"message":"hello ren"}'
curl -Ns localhost:8000/chat/stream -H 'content-type: application/json' \
-d '{"message":"count to three"}' # token-by-token SSEPass "tier": "fast" | "default" | "hard" in the body to override the model for a single turn. From conversation a pilot can build out a whole home — see the endpoint reference for the full surface (/identity, /memory, /threads, /ws/audio).
Operate
Docker
The repo ships a multi-stage Dockerfile (Python 3.12-slim, non-root user) and a docker-compose.yml. Set your key in .env, then:
cp .env.example .env # set ANTHROPIC_API_KEY docker compose up -d # build + start on :8000 # optional: bring up a Home Assistant sidecar too docker compose --profile ha up -d
In the container, Ren binds 0.0.0.0:8000 and persists everything to the ren_data volume mounted at /data — so REN_DB_PATH is /data/ren.db and REN_FILES_ROOT is /data/files. A built-in healthcheck polls /health every 30s. Build the image on its own with make docker.
Optional
Voice setup
Voice is opt-in. The STT/TTS/VAD models load only when enabled, so Ren boots fine without the ML dependencies installed (it just reports voice unavailable). To turn it on, add to .env:
REN_VOICE_ENABLED=true # optional tuning REN_VOICE_WAKE_ENABLED=false # continuous wake-word listening REN_VOICE_STT_MODEL=tiny # Whisper size REN_VOICE_TTS_VOICE=en_US-lessac-medium REN_VOICE_VAD_THRESHOLD=0.5 # Silero sensitivity
Restart Ren, then open http://127.0.0.1:8000/ for the built-in push-to-talk web client, or connect your own client to the ws://127.0.0.1:8000/ws/audio WebSocket. Speech-to-text uses Whisper, text-to-speech uses Piper, and voice-activity detection uses Silero VAD — all server-side and CPU-only.
Connect
Smart home quickstart
The fastest path is a local Philips Hue bridge — two variables and you are controlling lights. Add to .env:
REN_HUE_URL=http://192.168.1.x # your bridge IP REN_HUE_USERNAME=your-hue-api-token
Restart Ren and say (or POST) "show me my smart home accessories" — your Hue lights appear. From there you can assign devices to rooms, group them into scenes, and write automations that reference them by name:
"Add a room called Living Room." "Assign the lamp to the living room." "Create a scene called Movie Night that dims the lights." "Run Movie Night at 8pm every evening."
Persist your setup across restarts by pointing the path vars at real files: REN_HOME_GRAPH_PATH, REN_HOME_SCENES_PATH, REN_HOME_AUTOMATIONS_PATH (unset = in-memory only). Stuck? Say "run a health check on Ren" and it reports which connectors initialized. Every other platform — Home Assistant, HomeKit, Matter, Z-Wave, Sonos, Roku, SmartThings, EVs and more — is configured the same way; see the connector reference.
Trust
Data & privacy
Ren is local-first by construction. Everything it remembers stays in files on the machine you run it on:
./data/ren.db— a standard SQLite file holding all conversation memory, threads and reminders (path set byREN_DB_PATH). Open it with any SQLite browser; copy it to back up../data/ren_identity.key— Ren's persistent keypair, the seam for a future trust network../data/files— the sandbox the file tools are confined to (REN_FILES_ROOT). Path traversal outside it is refused; nothing is written elsewhere.