How to Manage Environment Variables in OpenWork: A Complete Configuration Guide

OpenWork uses the dotenv library to load configuration from .env files in three layers—local files, service-specific overrides, and process environment—allowing secure secret management without committing sensitive data to version control.

OpenWork relies heavily on environment variables for runtime configuration, from authentication tokens to workspace paths. Understanding how to properly manage these variables is essential for both local development and production deployments in the different-ai/openwork repository. This guide explains the complete environment variable lifecycle, from the initial loading mechanisms in load-env.ts to specific configuration options for tokens, ports, and development modes.

Three-Layer Configuration Loading

OpenWork implements a cascading configuration system that prioritizes security and flexibility. The loading order ensures that committed code never contains secrets while allowing overrides for different deployment environments.

Layer 1: Local Environment Files

The system first searches for /.env or /.env.local files adjacent to the service directory. These files load without overriding existing values, establishing baseline configuration for development. This implementation resides in ee/apps/inference/src/load-env.ts and similar service-specific loaders.

Layer 2: Service-Specific Overrides

Certain services implement additional environment file discovery. The den-worker-proxy searches upward through the directory tree for /.env.daytona, enabling per-Daytona environment configurations. This logic is implemented in ee/apps/den-worker-proxy/src/load-env.ts, allowing the proxy to locate environment files up to eight directories above its execution context using OPENWORK_DAYTONA_ENV_PATH.

Layer 3: Process Environment

Finally, dotenv.config({ override: false }) executes to ensure any variables set by your CI pipeline, Docker container, or shell session take precedence. Because the loading order follows file → file → process, system-level environment variables always win, making the system safe for production deployments where .env files may not exist.

Essential Environment Variables

OpenWork recognizes several critical environment variables that control authentication, workspace location, and development behavior.

Authentication and Security

  • OPENWORK_TOKEN: The primary bearer token for the OpenWork UI, auto-generated on first launch or read from the token store. This variable facilitates communication between the server and user interface.
  • OPENWORK_HOST_TOKEN: Grants administrative access to host-only routes, including secret management endpoints. The server generates this alongside the standard token during initialization.
  • OPENWORK_TOKEN_STORE: Overrides the default path for token persistence. When unset, tokens write to <config-dir>/tokens.json as determined by openworkConfigDir(). The TokenService class in apps/server/src/tokens.ts (lines 22-31) handles this resolution using path.resolve.

Workspace and Network Configuration

  • OPENWORK_WORKSPACE: Defines the root folder holding the user's OpenWork workspace. Defaults to the current working directory (process.cwd()).
  • OPENWORK_REMOTE_ACCESS: When set to true, binds the server to 0.0.0.0 instead of localhost, making the instance reachable from other hosts on the network.
  • OPENWORK_PUBLIC_HOST: Overrides the host reported in the runtime manifest, essential for NAT traversal and port-forwarding scenarios.
  • OPENWORK_PORT and OPENWORK_WEB_PORT: Define custom ports for the server and web interface. The resolvePort helper in scripts/dev-headless-web.ts (lines 70-95) validates port availability, requesting random free ports from the OS if these variables are unset.

Development and Testing Variables

  • OPENWORK_DEV_HEADLESS_WEB_REPLACE: Forces a fresh headless-web instance when running scripts/dev-headless-web.ts. Set to 1 or true to enable.
  • OPENWORK_DEV_HEADLESS_WEB_DEN_PROXY: Controls the embedded Den proxy. Defaults to true; set to 0 or false to disable.
  • OPENWORK_DEV_DEN_PROXY_TARGET: Specifies a custom URL for the Den proxy. The dev-headless-web.ts script normalizes this value with normalizeDenTarget and exposes it to Vite as VITE_DEN_API_BASE_URL (lines 117-138).
  • OPENWORK_EVAL_*: A series of flags (such as APP_SPECS=1 or DAYTONA=1) used exclusively by the evaluation suite in evals/specs/. These do not affect production runtime.

Frontend Build Variables

  • VITE_OPENWORK_URL and VITE_OPENWORK_TOKEN: Injected into the browser bundle during the Vite build process. These are populated from the generated runtime manifest. Never expose OPENWORK_HOST_TOKEN to these frontend variables.

Practical Configuration Examples

Creating a Local Development Environment

Create a .env.local file in your project root to store sensitive development credentials without committing them to version control:


# .env.local (never commit this file!)

OPENWORK_TOKEN=my-dev-token
OPENWORK_HOST_TOKEN=my-host-token
OPENWORK_WORKSPACE=/path/to/my/workspace
OPENWORK_REMOTE_ACCESS=1

Running pnpm dev:headless-web automatically picks up these values because load-env.ts processes .env.local before other configuration sources.

Customizing Token Storage Location

To store tokens in a temporary location for testing or CI environments:

export OPENWORK_TOKEN_STORE=/tmp/openwork-tokens.json
pnpm start

The server now reads and writes authentication tokens to /tmp/openwork-tokens.json instead of the default configuration directory. This override is processed in apps/server/src/tokens.ts (lines 24-31).

Managing Headless Web Sessions

Force a complete restart of the headless-web environment with fresh tokens:

pnpm dev:headless-web --replace

To preserve existing tokens during the restart:

pnpm dev:headless-web --replace --keep-tokens

The --replace flag checks process.env.OPENWORK_DEV_HEADLESS_WEB_REPLACE at line 31 of dev-headless-web.ts.

Configuring Custom Proxy Targets

Point the embedded Den proxy to a custom backend for integration testing:

export OPENWORK_DEV_DEN_PROXY_TARGET=https://custom-den.example.com
export OPENWORK_DEV_HEADLESS_WEB_DEN_PROXY=1
pnpm dev:headless-web

The script validates the target URL through normalizeDenTarget before injecting VITE_DEN_API_BASE_URL into the Vite environment.

Security Best Practices

Token Persistence and Permissions

When scripts/dev-headless-web.ts generates the runtime manifest containing URLs, tokens, and process IDs, it writes the file with mode 0o600 (owner-only permissions). This prevents accidental leakage of sensitive credentials to other system users.

Variable Precedence for Secrets

Because the loading mechanism uses override: false when processing .env files, you can safely template default values in committed .env.example files while overriding them with actual secrets in your shell environment or Docker secrets management. The TokenService class respects this precedence when resolving OPENWORK_TOKEN_STORE paths.

Separation of Concerns

Maintain strict separation between OPENWORK_TOKEN (UI access) and OPENWORK_HOST_TOKEN (administrative access). The host token grants elevated privileges for secret management routes and should never be exposed to frontend code or browser-accessible environment variables.

Summary

  • OpenWork loads environment variables in three layers: local .env files, service-specific overrides (like .env.daytona), and process environment variables.
  • The dotenv library handles initialization in ee/apps/inference/src/load-env.ts and related service loaders without overriding existing process variables.
  • Authentication tokens (OPENWORK_TOKEN and OPENWORK_HOST_TOKEN) auto-generate on first launch unless specified via environment variables or custom token store paths.
  • Development scripts like dev-headless-web.ts consume specific variables (OPENWORK_DEV_HEADLESS_WEB_REPLACE, OPENWORK_DEV_DEN_PROXY_TARGET) to control runtime behavior and proxy configuration.
  • Runtime manifests write with restrictive 0o600 permissions to prevent credential leakage.

Frequently Asked Questions

What is the precedence order for environment variables in OpenWork?

OpenWork follows a strict file-to-process hierarchy. First, it loads /.env and /.env.local from the service directory. Next, specific services like the den-worker-proxy search for /.env.daytona upward through the directory tree. Finally, dotenv.config({ override: false }) ensures that variables already present in the process environment (set by Docker, CI systems, or shell exports) take final precedence.

How do I securely store tokens in OpenWork?

Tokens persist to a JSON file determined by OPENWORK_TOKEN_STORE or defaulting to <config-dir>/tokens.json. The runtime manifest writes with mode 0o600 (owner-only read/write) to prevent unauthorized access. For production, set tokens via process environment variables rather than .env files, and never commit .env.local to version control.

Can I use a custom path for the token store file?

Yes. Set the OPENWORK_TOKEN_STORE environment variable to an absolute path before starting the server. The TokenService class in apps/server/src/tokens.ts (lines 22-31) resolves this path using path.resolve, allowing you to store tokens in tmpfs mounts, external volumes, or specific directories outside the default configuration folder.

What is the difference between OPENWORK_TOKEN and OPENWORK_HOST_TOKEN?

OPENWORK_TOKEN serves as the primary bearer token for UI-to-server communication, while OPENWORK_HOST_TOKEN grants administrative access to host-only routes such as secret management endpoints. The host token carries elevated privileges and should remain server-side only, whereas the standard token can safely populate VITE_OPENWORK_TOKEN for frontend authentication.

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 →