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.

API reference →Read the FAQ

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.
  • uv for dependency management, or Docker if you prefer the container path.

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
No API key handy? You can still run the full test suite and the 40-case eval offline — Claude is mocked: make test, make lint, and make eval all run without a key.

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-...
Never commit .env. It is gitignored — your key and tokens live only on the machine running Ren.

Core

VariableDefaultWhat it does
ANTHROPIC_API_KEYYour 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_TIERdefaultModel tier when a request does not specify one: fast | default | hard.
REN_HOST127.0.0.1Bind address. Stays loopback-only unless you change it.
REN_PORT8000TCP port the API and web client listen on.
REN_DB_PATH./data/ren.dbOn-device SQLite file holding all memory, threads and reminders. Gitignored, never synced.
REN_CHAT_TIMEOUT_S60Maximum seconds a /chat call may run before returning 504.

Files & safety

VariableDefaultWhat it does
REN_FILES_ROOT./data/filesSandbox root for the file tools. Any path traversal outside it is refused.
REN_ALLOW_DANGEROUS_TOOLSfalseSide-effecting tools (write, delete, export, device control) are gated off by default. Set true to unlock them globally — or enable per-thread.
REN_IDENTITY_ROOTfileProvenance of the identity key: file (PEM on disk) | mock (in-memory) | hardware (sovereign SE, later).
With 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

VariableDefaultWhat it does
REN_PERSONA_NAMERenWhat the assistant calls itself.
REN_PERSONA_INSTRUCTIONSFree-text personality overlay, e.g. "You answer concisely and dryly."
REN_PERSONA_FILEPath 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.

VariableDefaultWhat it does
REN_VOICE_ENABLEDfalseMaster switch. Off by default — the ML stack loads only when this is true.
REN_VOICE_WAKE_ENABLEDfalseContinuous wake-word listening. When off, audio is processed only after you start a session.
REN_VOICE_STT_MODELtinyWhisper model size for speech-to-text (CPU-only).
REN_VOICE_TTS_VOICEen_US-lessac-mediumPiper voice used for text-to-speech.
REN_VOICE_VAD_THRESHOLD0.5Silero 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.

Connector reference →
Migrating from an older build? Legacy WREN_* variable names are still honored as aliases (Ren logs a one-time deprecation warning). An explicit REN_* always wins.

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 SSE

Pass "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).


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.


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.

Only one voice session runs at a time. Because the speaker is physically present, voice sessions auto-approve dangerous tools — you can act on your home by speaking without flipping the global flag.

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.


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 by REN_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.
The only thing that leaves your network is the Claude API call you explicitly make. No telemetry, no usage analytics, no hosted account. The LAN hub announcement uses mDNS (UDP multicast) and never leaves your local network.
Full API reference →FAQBack home