Secure API Key Management with Environment Variables in ai-hedge-fund
The virattt/ai-hedge-fund repository eliminates hard-coded secrets by loading API credentials from environment variables into a centralized state object, then retrieving them through the get_api_key_from_state helper to ensure tokens are only accessible at runtime.
The virattt/ai-hedge-fund project handles sensitive credentials for OpenAI, Alpha Vantage, and Ollama services through a rigorous environment-variable architecture. This secure API key management strategy keeps authentication tokens out of version control while providing trading agents with seamless access to external data sources. By routing all credential access through a single utility in src/utils/api_key.py, the codebase maintains strict separation between secret configuration and business logic.
Architecture Overview: From Environment to Execution
The repository implements a three-layer defense that prevents accidental credential exposure. At the outer layer, environment variables supply raw secrets via a template file. These values flow into a global state object during application bootstrap in src/main.py, then get retrieved on-demand by services through a type-safe helper function.
Layer 1: Environment Configuration (.env.example)
The repository provides .env.example as a template that documents required secrets without exposing real values. Developers copy this file to .env and populate it with actual keys, or inject the variables directly through Docker, Kubernetes, or CI/CD secret managers.
# .env.example – Environment variable templates
# OpenAI LLM integration
OPENAI_API_KEY=your-openai-key-here
# Alpha Vantage market data
ALPHAVANTAGE_API_KEY=your-alpha-vantage-key
# Ollama self-hosted endpoint
OLLAMA_BASE_URL=http://localhost:11434
Layer 2: Runtime State Population
During application startup, src/main.py reads the environment variables and injects them into the workflow state. This state object acts as a secure container that travels through the agent execution pipeline, ensuring API keys remain available but isolated from direct global scope access.
Layer 3: Secure Retrieval via api_key.py
The src/utils/api_key.py file provides the get_api_key_from_state function, the sole authorized pathway for accessing credentials. This helper navigates the nested state structure—checking state["metadata"]["request"].api_keys—to extract specific keys only when requested by legitimate services.
# src/utils/api_key.py – Centralized credential retrieval
def get_api_key_from_state(state: dict, api_key_name: str) -> str:
"""Get an API key from the state object."""
if state and state.get("metadata", {}).get("request"):
request = state["metadata"]["request"]
if hasattr(request, "api_keys") and request.api_keys:
return request.api_keys.get(api_key_name)
return None
Practical Implementation in LLM Services
When constructing requests to external LLMs, the codebase uses the helper to inject authentication headers without exposing the raw key in service logic. The src/utils/llm.py file demonstrates this pattern, explicitly noting where extraction occurs.
# src/utils/llm.py – Secure key extraction for LLM requests
def build_llm_payload(state: dict, model: str, prompt: str):
# Extract API keys from state if available
api_key = get_api_key_from_state(state, "openai")
headers = {"Authorization": f"Bearer {api_key}"} if api_key else {}
return {
"model": model,
"prompt": prompt,
"headers": headers,
}
Key Files and Their Security Roles
- .env.example – Template documenting required environment variables without exposing real secrets.
- src/utils/api_key.py – Centralized helper that extracts API keys from the execution state, preventing scattered credential access.
- src/utils/llm.py – Demonstrates secure key retrieval when building external API requests.
- src/main.py – Application entry point that loads environment variables into the global state object.
- src/tools/api.py – Service layer wrapper that expects keys via the state-based helper for HTTP authentication.
Summary
- Environment isolation: All API credentials live in environment variables defined by
.env.exampletemplates, never in source code. - State-based routing: The
get_api_key_from_statefunction insrc/utils/api_key.pyprovides the exclusive pathway for credential retrieval, centralizing access control. - Service-layer abstraction: LLM and data services pull keys from the runtime state on demand, enabling secure header injection without hard-coded strings.
- CI/CD compatibility: The architecture supports secret injection through standard environment variable mechanisms used by Docker, GitHub Actions, and cloud platforms.
Frequently Asked Questions
How does ai-hedge-fund prevent API keys from being committed to Git?
The repository only commits the .env.example file containing placeholder values like your-openai-key-here. Actual credentials are loaded from a local .env file or CI/CD secrets manager at runtime, following the twelve-factor app methodology.
What happens if an API key is missing at runtime?
The get_api_key_from_state function returns None when a requested key is absent from the state object. Downstream services check for this value and either raise explicit configuration errors or skip authentication headers, prompting operators to set the missing environment variable.
Where is the get_api_key_from_state function defined?
The secure retrieval helper is implemented in src/utils/api_key.py. It extracts values from state["metadata"]["request"].api_keys, providing a single point of control for all credential access across the codebase.
Can this pattern support external secrets managers?
Yes. Because the system reads from environment variables during bootstrap in src/main.py, you can populate those variables from AWS Secrets Manager, HashiCorp Vault, or Kubernetes secrets without modifying the retrieval logic in src/utils/api_key.py.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →