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

VarWhat it controlsDefault
RALPHY_PROJECT_DIROverride project auto-detection — point at a specific checkout.(auto-detected)
RALPHY_HOMERoot for ~/.ralphy/ — projects from ralphy new, global config.$HOME/.ralphy
RALPHY_REPO_ROOTRepo root for ralphy skill new and other scaffold verbs.process.cwd()
RALPHY_BINThe path the installer recorded as the binary path.(set by install.sh)
RALPHY_BIN_DIRThe directory containing the binary. Used to detect Homebrew installs.(set by installer)
RALPHY_ASSETS_MANIFEST_URLOverride the companion-repo manifest URL.(compiled-in default)
RALPHY_DOCTOR_NO_UPDATE_CHECKSet to 1 to skip the 24h update check in doctor.unset
NO_COLORHonored by chalk — disables ANSI colors when set to any value.unset
HOMEResolves ~. Used by Claude installer + skill detection.(system)
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_API_KEY=sk-or-...
ELEVENLABS_API_KEY=xi-...
OPENROUTER_REFERER=https://yourdomain.example
OPENROUTER_TITLE=My UGC pipeline
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>/workspace/.ralph/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

ralphy config list                                         # everything
ralphy config get budgets.singleProject                    # dotted-path lookup
ralphy config set budgets.singleProject 5                  # auto-typed (number)
ralphy config set doctor.checkUpdates false                # auto-typed (boolean)
ralphy config set notes.lastBatch "spring-2026-001..010"   # string
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:
KeyTypeUsed by
doctor.checkUpdatesboolralphy doctor — set to false to skip the 24h update check
budgets.<scope>numberE_BUDGET_EXCEEDED gate (per-project / per-batch caps)
imports[]arrayglobal config only — populated by ralphy setup --import-profile
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.