Skip to main content
ralphy reads two API keys, a handful of optional environment overrides, the project’s .env, and a per-workspace JSON config. The precedence is fixed and documented here so a missing key in CI never silently picks up a different value than you expected.

Required env vars

Two keys gate every meaningful operation:
OPENROUTER_API_KEY
string
required
OpenRouter API key for every LLM + media model call. Get one at openrouter.ai/keys. ralphy setup pings the key against GET /api/v1/auth/key to verify.
ELEVENLABS_API_KEY
string
required
ElevenLabs API key for voiceover, music, and SFX generation, plus the Scribe transcription default. Get one at elevenlabs.io/app/settings/api-keys. ralphy setup pings against GET /v1/user.
Both are required for a green ralphy doctor. The CLI raises E_ENV_KEY_MISSING (exit 4) the first time it needs a missing key.

Optional env overrides

You’ll rarely need any of these — defaults are right for both dev and binary installs.

.env files

Every project carries a <project>/.env. When ralphy resolves a project root (see CLI overview), it reads .env and merges keys into process.envbut only for keys not already set. Real shell-exported variables always win. Order of precedence, lowest to highest:
  1. Compiled-in default (e.g. RALPHY_HOME = $HOME/.ralphy).
  2. <project>/.env.
  3. Real environment variables (export FOO=... in your shell, env FOO=... prefix on the command).
  4. CLI flag (--cwd <path> for the project root).
A typical .env:
OPENROUTER_REFERER and OPENROUTER_TITLE are optional headers OpenRouter uses for usage analytics. ralphy setup doesn’t manage them — set them by hand if you want them tracked.

.envrc + direnv

If you use direnv, a .envrc at the project root will auto-load when you cd in. The CLI doesn’t depend on direnv — .env is read directly — but the two coexist fine. ralphy setup writes to .env; if you keep .envrc in sync manually, your shell sees the keys without launching ralphy.

Global config file

Two files matter:
  • ~/.config/ralphy/config.json — global. Holds default_project_dir (the link from ralphy setup --link <path>) and imports[] (profiles you’ve imported).
  • <project>/.ralphy/config.json — per-workspace. Free-form key/value, managed by ralphy config.
The two are separate by design: global config is about which project ralphy points at; workspace config is about how that project behaves.

ralphy config

set does best-effort type inference: true/false become booleans, parseable numbers become numbers, everything else stays a string. Dotted paths build the nested object on the fly. Full surface: /reference/cli/config.

Reading config from code

The CLI uses cli/lib/config.tsloadConfig(), saveConfig(), getNestedValue(), setNestedValue(). The on-disk shape is unscoped JSON; the verb interprets dotted keys. Common keys today: There’s no enforced schema. The CLI reads what it expects and ignores the rest.

Putting it together

When ralphy generate image runs, it sees:
  1. --cwd (flag) — if set, this is the project root.
  2. Walk up from cwd looking for package.json#name = "ugc-cli".
  3. RALPHY_PROJECT_DIR (env) — if set and valid.
  4. ~/.config/ralphy/config.json#default_project_dir — if set and valid.
Then it reads <root>/.env (without overwriting process.env), checks OPENROUTER_API_KEY is set (raises E_ENV_KEY_MISSING if not), and proceeds.