Skip to content

Configuration (env)

Copy .env.example → .env. The only required variable is an LLM key.

VariableDefaultPurpose
LLM_PROFILEanthropicanthropic | openrouter | mixed — which provider profile (per-tier default models)
LLM_ROUTING—Per-role preset: fast (Groq worker) | volume (OpenRouter worker) — see Role routing
ANTHROPIC_API_KEY—API key for the Anthropic profile
OPENROUTER_API_KEY—API key for the OpenRouter profile (cheaper)
GROQ_API_KEY—API key for the Groq worker (used by LLM_ROUTING=fast)
QA_TESTCASE_LANGEnglishLanguage for generated test cases, e.g. Ukrainian / uk
BROWSER_BACKENDliblib (in-process Playwright) | cli — how the browser is driven
BROWSER_CHANNEL—chrome to use real Chrome (helps with OAuth)
MAX_REPAIR2Max self-repair attempts per failing spec (keep-best)
LANGFUSE_BASE_URL—Langfuse — cloud or self-hosted (optional)
LANGFUSE_PUBLIC_KEY—Langfuse public key
LANGFUSE_SECRET_KEY—Langfuse secret key
ANTHROPIC_API_KEY=sk-ant-...

By default each profile uses its own per-tier models. LLM_ROUTING optionally layers a cheap worker over any profile while keeping the strong reasoner — one flag picks where the mechanical steps (identify elements, generate code, repair) run:

LLM_ROUTINGWorkerNotes
unset (default)the profile’s own per-tier modelsno routing
fastGroq llama-3.3-70b-versatilelowest latency / cost (needs GROQ_API_KEY)
volumeOpenRouter deepseek/deepseek-chatmodel breadth (needs OPENROUTER_API_KEY)

In every preset the reasoner — designing test cases and the Pilot verdict — stays on Anthropic claude-opus-4-8 for judgment quality. Override any role with CAIRN_ROLE_WORKER / CAIRN_ROLE_REASONER=provider:model, or pass --routing <preset> on explore / design / automate to set it per run. Per-run, per-role cost (tokens + $) is printed in the run summary — see ADR 0011.

The decision layer (0.8.0+) lets a System One model answer Cairn’s pick-from-a-list steps. It is off unless DECIDER names a provider, and a key on its own changes nothing.

VariableDefaultPurpose
DECIDERoffjev | laya | compat (--decider overrides it for one run)
DECIDER_USESrepair-triage (in shadow mode: every use point)Use points to enable: repair-triage, coverage, locator-heal (which needs repair-triage). An unknown name is an error
DECIDER_SHADOW01 = record the answers in runs/<id>/decider-shadow.json and act on none (--decider-shadow). Needs a provider
DECIDER_MIN_CONFIDENCE0.75Below it an answer is ignored and the current path runs
DECIDER_TIMEOUT_MS10000Per call, one retry on 429/5xx included
DECIDER_MAX_CALLS200Per-run ceiling on decisions (separate from the LLM call budget)
DECIDER_MODELjev-latestLaya picks its checkpoint by language unless pinned: multilingual for non-English apps
TYPESAFE_API_KEY—jev only (required)
TYPESAFE_BASE_URLhttps://api.typesafe.aijev only. Only an https://*.typesafe.ai address is accepted
DECIDER_BASE_URL—laya / compat only (required), e.g. http://127.0.0.1:8000
LAYA_API_KEY—laya only: the token laya-serve was started with
DECIDER_API_KEY—compat only

cairn doctor shows the provider, where the data goes and the latency of one real call. A misconfiguration fails at start, with the reason.