How OpenClaude Loads Provider Environment Files at Startup

OpenClaude loads provider environment files by first reading the global .env with dotenv, then extracting and sanitizing provider-specific variables in providerConfig.ts, and caching the result for the CLI session.

The provider configuration system in OpenClaude controls how each model integration receives its credentials, endpoints, and settings. According to the Gitlawb/openclaude source code, this configuration is constructed from environment files through a three-stage pipeline that ensures security and consistency.

Step 1: Load the Global .env File

The bootstrap process begins in src/bootstrap/state.ts, where the CLI calls the dotenv package to populate process.env.

// src/bootstrap/state.ts
import { config as loadDotEnv } from 'dotenv';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const projectRoot = join(__dirname, '..', '..');

loadDotEnv({ path: `${projectRoot}/.env` });

This single call reads the repository-root .env file and injects all key-value pairs into the Node.js environment. The path resolution ensures the file is loaded relative to the project structure, not the current working directory.

Step 2: Merge Provider-Specific Variables

After the global file loads, the provider-configuration module at src/services/api/providerConfig.ts scans process.env for variables matching each provider's naming convention.

// src/services/api/providerConfig.ts
export function resolveProviderRequest(
  provider: ProviderId,
  env: Record<string, string | undefined> = process.env,
): ResolvedProviderRequest {
  const vars = pickProviderEnvVars(provider, env);
  // …construct a ResolvedProviderRequest from `vars`
}

The helper pickProviderEnvVars performs two critical sanitization tasks:

  • Filters placeholder sentinels — Removes entries containing ${ that may leak from dotenv templates or Windows-style variable expansions
  • Normalizes malformed values — Strips literal ${VAR} strings that can appear in certain shell environments

Supported provider variables follow predictable patterns: OPENAI_API_KEY, ANTHROPIC_API_KEY, CLAUDE_CODE_GEMINI_PROJECT_ID, and similar prefixed keys.

Step 3: Cache the Resolved Configuration

To prevent redundant environment reads and guarantee consistency, src/bootstrap/state.ts implements a singleton-style cache:

// src/bootstrap/state.ts (excerpt)
let cachedProviderRequest: ResolvedProviderRequest | undefined;

export function getProviderRequest(provider: ProviderId) {
  if (!cachedProviderRequest) {
    cachedProviderRequest = resolveProviderRequest(provider);
  }
  return cachedProviderRequest;
}

The first call to getProviderRequest triggers resolution; subsequent calls return the identical cached object. This ensures every component receives the same fully-resolved configuration throughout the CLI run.

Key Files in the Loading Pipeline

File Responsibility
src/bootstrap/state.ts Entry point; loads global .env via dotenv.config() and caches resolved requests
src/services/api/providerConfig.ts Parses provider-specific variables, removes template sentinels, builds ResolvedProviderRequest
src/utils/providerProfiles.ts Utilities for cleaning template/dotenv sentinels post-load
src/utils/providerFlag.ts Documents sentinel filtering logic for endpoints

Security Considerations in Provider Env Loading

The OpenClaude provider environment loading system implements defensive filtering at multiple layers:

  • Sentinel detection — Any value containing ${ is treated as a template placeholder and discarded
  • Strict key matching — Only variables matching known provider prefixes are extracted
  • Single-read caching — Environment is never re-parsed after initial load, preventing mid-session tampering

These safeguards prevent accidental credential leakage from incomplete .env configurations or shell environment pollution.

Summary

  • Global loading — src/bootstrap/state.ts calls dotenv.config() to read the repository-root .env file
  • Provider extraction — src/services/api/providerConfig.ts filters process.env for provider-specific keys and strips template sentinels
  • Request caching — Resolved configurations are cached in bootstrap state to ensure consistency across the CLI session
  • Sentinel removal — Placeholder patterns like ${VAR} are automatically discarded to prevent credential leaks

Frequently Asked Questions

Where does OpenClaude look for the .env file?

OpenClaude resolves the .env path relative to src/bootstrap/state.ts's location, traversing up two directory levels to reach the repository root. This ensures the file is found regardless of the working directory from which the CLI is invoked.

What happens if a provider environment variable contains a template placeholder?

The pickProviderEnvVars helper in src/services/api/providerConfig.ts detects values containing ${ and deletes them from the configuration. This prevents accidental use of unexpanded shell variables or copy-pasted template strings as actual credentials.

Why does OpenClaude cache the provider configuration?

Caching in getProviderRequest() guarantees that all components reference identical credential sets throughout a CLI session. Without caching, environment mutations or filesystem changes could cause inconsistent behavior between different model integrations.

Which provider environment variable prefixes are supported?

As implemented in src/services/api/providerConfig.ts, OpenClaude recognizes provider-prefixed keys including OPENAI_*, ANTHROPIC_*, and CLAUDE_CODE_GEMINI_*. The system uses dynamic key construction based on the ProviderId enum to match variables to their respective integrations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →