How HolaOS Manages Configuration Settings: A Layered Runtime System Explained
HolaOS centralizes runtime configuration in a JSON document with environment variable overrides, providing a three-layer precedence system (file → env → defaults) for flexible, container-ready deployments.
The HolaOS configuration system, implemented in runtimeConfigPath() and related utilities in runtime/api-server/src/runtime-config.ts, gives operators two ways to control application behavior: a persistent JSON file for reproducible state and environment variables for dynamic, containerized environments. This article examines the complete configuration flow from disk to strongly-typed runtime object.
How Configuration Loading Works
HolaOS loads configuration through three distinct stages that progressively merge sources and validate the result.
Stage 1: Loading the Raw JSON Document
The loadRuntimeConfigDocument() function determines where to look for configuration by calling runtimeConfigPath(). This path resolver checks the HOLABOSS_RUNTIME_CONFIG_PATH_ENV environment variable first, then falls back to the default sandbox state directory. If the file exists, it parses the JSON; otherwise, it returns an empty document structure.
// Internal implementation detail from runtime/api-server/src/runtime-config.ts#L70-L78
// Path resolution prioritizes HOLABOSS_RUNTIME_CONFIG_PATH_ENV
const configPath = runtimeConfigPath(); // → sandbox/state/runtime-config.json or custom path
const rawDocument = loadRuntimeConfigDocument(configPath);
Stage 2: Merging with Environment Variables
The loadRuntimeConfigPayload() function extracts nested sections (runtime, providers, integrations, capabilities) and normalizes each field. For every property, it applies precedence-based resolution: JSON value first, then environment variable fallback, finally hard-coded default.
Key environment variables include:
HOLABOSS_SANDBOX_AUTH_TOKEN_ENVHOLABOSS_USER_ID_ENVHOLABOSS_MODEL_PROXY_KEY_ENV
The firstEnvValue() helper implements this fallback chain. Boolean and list values receive specialized normalization through normalizeBool() and normalizeStringList() to handle string representations consistently.
// From runtime/api-server/src/runtime-config.ts#L122-L158
// Environment variables override JSON values only when JSON is absent
const mergedPayload = loadRuntimeConfigPayload({
preferEnv: false, // JSON takes precedence
});
Stage 3: Building the Typed Config Object
The resolveProductRuntimeConfig() function constructs a ProductRuntimeConfig instance from the merged payload. This stage performs runtime validation: when requireAuth: true, the function throws if no authentication token is present; similarly for requireUser.
// From runtime/api-server/src/runtime-config.ts#L103-L112
const config = resolveProductRuntimeConfig({
requireAuth: true, // Validates HOLABOSS_SANDBOX_AUTH_TOKEN presence
requireUser: true, // Validates HOLABOSS_USER_ID presence
});
Accessing Configuration in Application Code
Components retrieve configuration through two patterns depending on their architecture.
Direct Function Calls
Simple utilities call resolveProductRuntimeConfig() directly. The runtimeConfigHeaders() function uses this approach to build HTTP headers for downstream services, ensuring updates propagate immediately to outgoing requests.
import { runtimeConfigHeaders } from "@/runtime/api-server/src/runtime-config";
const headers = runtimeConfigHeaders({ requireAuth: true });
// Produces: { "X-API-Key": "...", "X-Holaboss-User-Id": "..." }
fetch("https://model-proxy.example/api", { headers });
Injectable Service Pattern
API handlers use FileRuntimeConfigService, which encapsulates loading, status checking, and updating behind a clean interface. This class abstracts the underlying file operations and re-loading logic.
import { FileRuntimeConfigService } from "@/runtime/api-server/src/runtime-config";
const configService = new FileRuntimeConfigService();
// Read-only access to current configuration
const current = await configService.getConfig();
// Check if configuration exists on disk
const exists = await configService.status(); // → { exists: boolean }
Updating Configuration at Runtime
The updateRuntimeConfigDocument() function receives partial payloads from client requests, merges them into the existing JSON structure while preserving unknown fields, and persists the result via writeRuntimeConfigDocument().
After saving, the service calls resolveProductRuntimeConfig() to refresh the in-memory view, ensuring subsequent reads reflect the updated state.
// From runtime/api-server/src/runtime-config.ts#L88-L97
await configService.updateConfig({
desktop_browser_enabled: true,
desktop_browser_url: "https://my-browser.local",
unknown_field: "preserved", // Not in TypeScript interface but kept in JSON
});
Configuration Precedence Explained
HolaOS implements deterministic, predictable layering:
| Precedence | Source | Typical Use Case |
|---|---|---|
| 1 (Highest) | runtime-config.json |
Reproducible deployments, version-controlled defaults |
| 2 | Environment variables (HOLABOSS_*) |
Container secrets, dynamic cloud assignments |
| 3 (Lowest) | Hard-coded defaults | DEFAULT_MODEL = "gpt-5.4" |
This design satisfies two operational modes: static file management for development and GitOps workflows, and environment injection for Kubernetes, Docker, and serverless platforms.
Complete Configuration Example
// Full workflow: load, inspect, modify, and apply configuration
import {
resolveProductRuntimeConfig,
FileRuntimeConfigService,
runtimeConfigHeaders,
} from "@/runtime/api-server/src/runtime-config";
// 1. Resolve with validation
const cfg = resolveProductRuntimeConfig({
requireAuth: true,
requireUser: true,
});
console.log(cfg.model); // → "gpt-5.4" (from JSON or default)
console.log(cfg.authToken); // → from HOLABOSS_SANDBOX_AUTH_TOKEN_ENV if JSON absent
// 2. Service-based updates
const service = new FileRuntimeConfigService();
await service.updateConfig({ model: "gpt-5.5" });
// 3. Headers automatically reflect changes
const headers = runtimeConfigHeaders({ requireAuth: true });
Summary
- Configuration lives in
runtime-config.jsonunder the sandbox state directory, with path override viaHOLABOSS_RUNTIME_CONFIG_PATH_ENV - Three-stage loading: raw document → env merging → typed validation via
resolveProductRuntimeConfig() - Environment variables provide fallback values when JSON fields are absent, not override
FileRuntimeConfigServiceencapsulates read, status-check, and update operations for dependency injection- Updates preserve unknown JSON fields and immediately refresh the resolved configuration
runtimeConfigHeaders()ensures downstream service calls always use current settings
Frequently Asked Questions
How do I override a HolaOS setting without modifying the JSON file?
Set the corresponding environment variable. HolaOS checks HOLABOSS_* variables after reading the JSON document, using firstEnvValue() to apply fallbacks. For example, export HOLABOSS_MODEL_PROXY_KEY_ENV=sk-... provides the API key without touching runtime-config.json.
What happens if runtime-config.json does not exist?
loadRuntimeConfigDocument() returns an empty document structure, and all configuration resolves from environment variables and hard-coded defaults. The system does not fail; it operates in "env-only" mode until a configuration file is created.
How does HolaOS handle configuration updates without restarting?
The FileRuntimeConfigService.updateConfig() method writes changes to disk and immediately calls resolveProductRuntimeConfig() to rebuild the typed configuration object. Components reading through the service or calling runtimeConfigHeaders() receive updated values on their next access—no restart required.
Where is the configuration file located by default?
runtimeConfigPath() returns sandbox/state/runtime-config.json relative to the working directory unless HOLABOSS_RUNTIME_CONFIG_PATH_ENV is set. This default path supports HolaOS's sandbox isolation model while remaining overrideable for custom deployments.
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 →