Environment variables

Helmr names environment variables according to the environment that owns them:

  • A dedicated Helmr process uses direct configuration names such as DATABASE_URL, CONTROL_PLANE_ADDR, and WORKER_RESOURCE_ID. Repeating HELMR_ inside a process-specific environment adds no ownership information.
  • HELMR_ is reserved for public client configuration and values that cross into an environment Helmr does not exclusively own, such as a user’s shell or a Computer guest. The CLI variables below are examples.
  • Established ecosystem variables such as AWS_*, HTTP_PROXY, and NO_PROXY keep their standard names where supported by the owning tool. Platform integration clients use the explicit OUTBOUND_PROXY_URL contract below.

Environment variable names are an exact, case-sensitive contract. Helmr does not read legacy aliases. Text, numeric, boolean, and duration settings ignore surrounding whitespace. Passwords and tokens are opaque and are read exactly as provided. Base64 root keys must be canonical without surrounding whitespace. This page covers supported operator and client configuration. Variables owned entirely by the guest image, tests, or development tooling remain internal.

CLI

Variable Purpose
HELMR_API_URL Control-plane base URL.
HELMR_API_KEY Bearer token for CLI or HelmrClient.
HELMR_PROJECT Project ID for Environment and env commands when --project is absent. With an API key, it must match the key’s Project.
HELMR_ENV Environment ID for Environment commands when --env is absent. With an API key, it must match the key’s Environment.
HELMR_CONFIG_DIR CLI state directory override.

Role grant and member permission commands ignore both variables: there, omitting --project or --env means organization-wide or unfiltered, so an ambient default would change a grant’s scope.

HelmrClient does not read these variables automatically. Pass the URL and API key from your application’s configuration to its constructor.

Control Plane

Required: DATABASE_URL, CAS_URI, CLICKHOUSE_URL, DEPLOYMENT_RUNTIME_DESCRIPTOR_PATH, PLATFORM_STORE_URI, WORKER_HOST_CREDENTIAL_SIGNING_KEY, AUTH_KEY, ENCRYPTION_KEY, COMPUTER_FENCING_KEY. Configure GITHUB_OAUTH_CLIENT_ID and GITHUB_OAUTH_CLIENT_SECRET together to enable GitHub login; both may be omitted.

Deployment uploads require the same explicit process configuration in Managed Cloud and self-hosted installations. There are no server-side capacity defaults:

Variable Purpose
DEPLOYMENT_UPLOAD_PROCESS_CONCURRENCY Positive maximum active object uploads, including preflight, in one Control Plane process.
DEPLOYMENT_UPLOAD_ORGANIZATION_CONCURRENCY Positive maximum for one organization in that process, no greater than the process maximum. Set them equal when one organization may use all capacity.
DEPLOYMENT_UPLOAD_IDLE_TIMEOUT Maximum interval without body progress, including blocked storage; a duration such as 2m, at least 1ms.
DEPLOYMENT_UPLOAD_MAX_DURATION Absolute duration of one admitted body transfer, at least the idle timeout; a duration such as 2h.
CONTROL_PLANE_HTTP_IDLE_TIMEOUT HTTP keepalive idle time between requests, distinct from upload progress; defaults to 2m. Set it longer than the reverse proxy’s pooled-connection idle time.

Upload capacity is per process, not a cluster-wide quota or reserved tenant share. When full, the server returns a retryable 429 with Retry-After. Organization caps do not guarantee fairness or prevent one actor using multiple organizations. Preflight is bounded to 30 seconds. After authorization, descriptor validation and storage preflight, transfers release ordinary API concurrency but retain upload capacity until transfer work and input cleanup complete. CPU, memory, database and network resources are still shared; measure headroom under ordinary traffic when choosing capacity.

The server duration bounds one admitted transfer. The CLI deadline includes capacity waiting and transfer, so allow retry headroom rather than setting both deadlines equal. A shorter caller, ingress or storage limit can terminate an operation first. Coordinate upload inactivity limits with ingress timeouts; HTTP keepalive is a separate setting. Runtime examples are starting points for measurement, not production capacity recommendations.

Environment execution limits must also be configured explicitly, on both the control plane and the dispatcher, with the same values. They have no implicit defaults. Set positive integer values appropriate for your deployment. The values apply to every Environment and take effect when the processes restart; a lowered admission burst applies at the next admission.

Variable Purpose
ENVIRONMENT_MAX_RESIDENT_COMPUTERS Maximum Computers holding an execution allocation at once.
ENVIRONMENT_MAX_CPU_MILLIS Bound on physical whole-vCPU reservations across the Environment, in millicores. A fractional request rounds up: cpu: 0.5 reserves 1000 millicores. A non-multiple of 1000 leaves its remainder unusable. A Computer that cannot fit on its own is rejected at creation.
ENVIRONMENT_MAX_MEMORY_BYTES Bound on memory reservations across the Environment. A Computer larger than this bound is rejected at creation.
ENVIRONMENT_MAX_RESERVED_STORAGE_BYTES Bound on reserved logical Computer storage. Each Computer reserves 32 GiB; a lower bound rejects fresh Computer creation.
ENVIRONMENT_MAX_OUTSTANDING_ADMISSIONS Maximum queued and running Turns.
ENVIRONMENT_ADMISSION_RATE_PER_SECOND Refill rate for new Turn admission tokens.
ENVIRONMENT_ADMISSION_BURST Maximum admission tokens; one new Turn consumes one token.

Starting execution beyond the aggregate CPU, memory or resident Computer bound is refused; queued work that cannot fit waits and reports the Environment limit as its reason. Retrying an accepted request does not consume another token. Disk reservations are distinct from physical CPU/memory allocation and from measured stored bytes. These resource and admission bounds do not promise a monetary spend ceiling.

Requester ancestry for created Sessions is limited to a depth of 8. Computer preparation, image builds and the start of execution each have a fixed 10-minute deadline.

Diagnostic ingestion requires explicit positive integer limits. The dispatcher also uses these limits for diagnostic export and requires the export batch settings below:

Variable Purpose
DIAGNOSTIC_CHUNK_BYTES Maximum bytes in one log data record, at most 16 MiB.
DIAGNOSTIC_SOURCE_BYTES, DIAGNOSTIC_SOURCE_RECORDS Pending byte and record ceilings for one producer.
DIAGNOSTIC_ENVIRONMENT_BYTES, DIAGNOSTIC_ENVIRONMENT_RECORDS Pending ceilings across an Environment.
DIAGNOSTIC_QUEUE_BYTES, DIAGNOSTIC_QUEUE_RECORDS Pending ceilings across the diagnostic queue.
DIAGNOSTIC_DB_MAX_CONNECTIONS Maximum connections in each process’s dedicated diagnostic pool, additional to its ordinary database pool.
DIAGNOSTIC_EXPORT_BATCH_RECORDS Dispatcher: maximum records per diagnostic export batch.
DIAGNOSTIC_EXPORT_BATCH_BYTES Dispatcher: maximum data bytes per diagnostic export batch, at least DIAGNOSTIC_CHUNK_BYTES.

Byte ceilings must satisfy chunk ≤ source ≤ Environment ≤ queue. Record ceilings must satisfy source ≤ Environment ≤ queue. Gap and end records count toward the record limits. These ceilings do not reserve capacity for a producer or Environment. A busy or full queue asks producers to retry; diagnostic pool exhaustion leaves the ordinary pool available for lifecycle requests.

Missing, invalid or inconsistent diagnostic or deployment-upload settings prevent the relevant service from starting. Before a rollout, load each service’s intended environment and run its binary with check-config:

control-plane check-config
dispatcher check-config

These commands use the same environment loaders as service startup and exit nonzero on invalid settings. They do not start services, connect to dependencies, read the Runtime descriptor, or check credentials against external services. A successful check does not prove full startup or availability. Runtime sink failures and queue exhaustion continue to use bounded retry and backpressure; separate pools do not isolate a shared PostgreSQL outage. Accepted records retain their configured expiry.

Deployment mode: DEPLOYMENT_MODE defaults to self-hosted. First-organization setup requires a deployment operator session and a separately authenticated ordinary account. Managed-cloud organization creation follows the configured creation policy. See authentication for operator enrollment.

Regions and Worker Groups are PostgreSQL resources managed through the Admin API and Console. Control Plane startup does not reconcile them from process configuration, and a deployment may start with neither resource.

An optional startup bootstrap seeds one Region and one execution Worker Group. Set BOOTSTRAP_ENABLED=true. When the named Worker Group does not exist, BOOTSTRAP_WORKER_TOKEN is also required. BOOTSTRAP_REGION_ID and BOOTSTRAP_WORKER_GROUP_NAME default to default. BOOTSTRAP_REGION_DISPLAY_NAME and BOOTSTRAP_REGION_LOCATION are optional. Bootstrap creates missing resources and never updates an existing Region or Worker Group. Changing either bootstrap identity can therefore create another missing seed; it does not rename or delete an existing resource. When needed, the token must use the hlmr_wgt_ format; only its SHA-256 hash is stored in PostgreSQL.

BOOTSTRAP_REGION_ID is an opaque Helmr identifier, not a provider Region or DNS name. Its normalized UTF-8 value must be 1–255 bytes and contain no surrounding whitespace or control characters.

Deployment operators use separate, passkey-authenticated identities. Ordinary user email addresses never confer deployment authority. Issue enrollment through the local deployment command described in the authentication guide.

Optional: CONTROL_PLANE_ADDR and APP_ORIGIN. APP_ORIGIN is the canonical browser/API origin used for login callbacks, Console links and Slack setup. It can be private HTTPS if users’ browsers can reach it.

SLACK_TRANSPORT selects http (default), socket or disabled for both Control Plane and Dispatcher. It is deployment-wide and is read-only in Console. Socket Mode receives events through outbound WSS; HTTP mounts per-registration event and interaction callbacks. Disabled rejects setup and starts no Slack delivery workers. Dedicated app credentials are organization-managed encrypted database records, not process environment variables.

OUTBOUND_PROXY_URL is an optional absolute HTTP(S) proxy origin for platform GitHub OAuth, Slack OAuth/API/Socket and Resend traffic. An empty value means explicit direct access. There is no automatic direct fallback or NO_PROXY bypass. The proxy must support CONNECT to HTTPS/WSS targets. These clients do not inherit ambient HTTP_PROXY or HTTPS_PROXY. PostgreSQL, configured ClickHouse, S3/KMS and internal readiness/control-plane clients use direct service paths; this setting is not a guest or worker-build egress policy. In the private reference, ClickHouse must have a private route and narrowly scoped security rules. See private deployments.

CAPACITY_TOKEN enables and authenticates the capacity API used by trusted deployment automation, including an operator-supplied scaler. It must be canonical unpadded base64url that decodes to exactly 32 bytes. The scaler sends the same value as a Bearer token over HTTPS outside localhost. Possession grants the complete capacity API for the deployment, so store it as a secret and provide it only to the Control Plane and trusted scaler. When it is unset, capacity API requests are rejected. See custom capacity scaling for setup and rotation.

ClickHouse telemetry: CLICKHOUSE_URL is required. Set CLICKHOUSE_USER when the service user is not default, and set CLICKHOUSE_PASSWORD when the service requires a password.

AUTH_KEY, COMPUTER_FENCING_KEY, ENCRYPTION_KEY, and WORKER_HOST_CREDENTIAL_SIGNING_KEY are distinct single roots. Each must be base64 and decode to exactly 32 bytes. Every Control Plane replica uses the same values. Online rotation and multi-key verification are not supported.

Computer data keys have a separate Control Plane wrapping root:

  • Self-hosted deployments require COMPUTER_WRAPPING_KEY_ID (a stable, nonempty identifier) and COMPUTER_WRAPPING_KEY (base64, exactly 32 bytes). All Control Plane replicas must use the same values. Preserve this key and identifier with database backups; replacing either makes existing Computer keys unreadable.
  • Managed-cloud deployments require COMPUTER_KMS_KEY_ARN, the full ARN of a symmetric KMS key. The Control Plane uses native AWS credentials and the ARN’s region. Its identity needs encrypt permission on that key and decrypt permission on every wrapping key still referenced by retained Computer keys. Retain those KMS keys; changing the configured ARN to another key in the same region only affects newly wrapped keys. Cross-region wrapping-key migration is not supported.
  • Wrapping keys and provider credentials belong only to the Control Plane. Workers receive scoped data keys through authenticated runtime authority. Provider errors never fall back to local wrapping material.

Email delivery is disabled by default. Set EMAIL_PROVIDER to choose a sender:

Provider Required variables Optional variables
none None. This is the default when no email settings are present. None
log EMAIL_PROVIDER=log Sign-in codes and invitation links are written to the Control Plane log instead of being sent. For local development only; rejected when DEPLOYMENT_MODE is managed-cloud.
smtp EMAIL_PROVIDER=smtp, SMTP_ADDR, EMAIL_FROM SMTP_USERNAME, SMTP_PASSWORD
resend EMAIL_PROVIDER=resend, RESEND_API_KEY, EMAIL_FROM None

The configured sender delivers sign-in links and member invitations. Without a sender, members can’t be invited.

EMAIL_FROM must be an email address or display-name address accepted by the selected provider, such as Helmr <noreply@example.com>.

Database bootstrap command

control-plane database-bootstrap [reset] uses a separate administrative connection to create or reset the application database role. These variables are command inputs; the long-running Control Plane does not read the administrative credentials.

Variable Purpose
DATABASE_ADMIN_HOST Required administrative PostgreSQL host.
DATABASE_ADMIN_PORT Administrative PostgreSQL port. Defaults to 5432.
DATABASE_ADMIN_USERNAME Required administrative role. It must differ from the application role in DATABASE_URL.
DATABASE_ADMIN_PASSWORD Required administrative role password.
DATABASE_NAME Required database name. DATABASE_URL must target the same name.
DATABASE_URL Required application connection URL. It must target the administrative endpoint with TLS, and include the application role and password.

Dispatcher

Required: DATABASE_URL, CLICKHOUSE_URL, COMPUTER_FENCING_KEY, ENCRYPTION_KEY, and CONTROL_PLANE_URL.

CONTROL_PLANE_URL must be the same reachable Control Plane endpoint used by Workers. Each Dispatcher probes its /readyz endpoint and requires 120 seconds of uninterrupted healthy samples before fencing stale Worker observations. Failures, missed samples and Dispatcher restarts reset this recovery window.

The dispatcher uses the same ENCRYPTION_KEY as the Control Plane to encrypt CA signers when it creates protected Computers for scheduled Agent admissions.

The dispatcher uses the same single base64-encoded 32-byte COMPUTER_FENCING_KEY as the Control Plane service.

Worker

Worker log buffering requires WORKER_LOG_CHUNK_BYTES, WORKER_LOG_BUFFER_BYTES and WORKER_LOG_BUFFER_RECORDS as positive integers. The chunk size must fit the 16 MiB transport limit and the control plane’s DIAGNOSTIC_CHUNK_BYTES; the buffer byte limit must be at least one chunk. Record count must fit a positive int32. These are per-producer memory limits, not durable queue reservations.

Required for every Worker: CONTROL_PLANE_URL, CAS_URI, PLATFORM_STORE_URI, WORKER_RESOURCE_ID, WORKER_POOL_NAME, WORKER_ENROLLMENT_TOKEN_FILE, CHECKPOINT_ENCRYPTION_KEY, JAILER_UID, JAILER_GID, WORKER_NETWORK_LINK_POOL, WORKER_NETWORK_TRANSLATION_POOL, WORKER_NETWORK_RESOLVER_IPV4, and WORKER_NETWORK_BLOCKED_IPV4_CIDRS. The blocked-prefix value is a canonical, ordered JSON array; use [] only when the deployment intentionally supplies no additional blocked destinations. Built-in reserved-address, metadata, host and peer restrictions still apply.

Network installation settings are shared between the Control Plane and Workers:

Variable Default Purpose
CONTROL_PLANE_NETWORK_PRIVATE_BUSINESS_CIDRS [] Canonical IPv4 RFC1918 prefixes eligible for authored private network grants.
CONTROL_PLANE_NETWORK_BLOCKED_IPV4_CIDRS [] Additional management or privileged prefixes denied by every eligible Worker.
WORKER_NETWORK_PRIVATE_BUSINESS_CIDRS [] The Worker’s approved private business ranges. Must be contained in the Control Plane ceiling.
WORKER_NETWORK_BLOCKED_IPV4_CIDRS Required The Worker’s additional denied ranges. Must cover the Control Plane’s denied ranges.

All four values are canonical, ordered JSON arrays of IPv4 CIDRs. Private business ranges must not overlap denied ranges. An empty private ceiling denies RFC1918 egress even when a Template omits network. For example, permitting ["10.42.0.0/16"] requires matching installation configuration and actual private routing/DNS; a Template domain grant additionally needs an ipRanges bound within that ceiling. An infrastructure grant alone does not add a Template domain grant.

A Worker may use a stricter ceiling or broader denies. The Control Plane rejects allocation delivery and renewal when the Worker is more permissive or cannot report the network enforcement contract. Update and qualify Workers before admitting policies that depend on this contract, and drain older execution before changing installation restrictions. Existing Computers retain their creation Template’s policy; a Template redeployment does not edit it.

The Worker reads its Worker Group enrollment token from the strict-permission token file and presents it as a Bearer credential over TLS. The token selects the Worker Group; the Worker does not configure a group ID. Control Plane validates the Pool enrollment against that group, records token use, creates the authoritative Worker-instance identity, and issues a per-instance host secret stored at WORKER_HOST_SECRET_PATH. The Worker exchanges that host secret for short-lived host credentials that authenticate its requests. WORKER_RESOURCE_ID remains an opaque deployment-owned locator for the physical Worker. Provider identity and infrastructure inventory are deployment responsibilities rather than Control Plane authentication inputs.

Enrollment returns a worker_resource_custody conflict while any prior Host for the same Group and resource locator retains an unfenced VM allocation, including private preparation VMs. A lost status alone does not prove physical cleanup. The prior Host remains visible to the capacity provider until its physical absence is confirmed; registration cannot hide it behind a new Host identity.

WORKER_WORK_DIR and WORKER_IMAGES_DIR select Worker state and image directories. The following advanced settings connect the Worker to binaries and host layout supplied by its deployment image:

Variable Default Purpose
FIRECRACKER_PATH firecracker Firecracker binary.
CPU_TEMPLATE_HELPER_PATH cpu-template-helper Firecracker CPU-template helper binary.
JAILER_PATH jailer Firecracker jailer binary.
MKFS_EXT4_PATH /usr/local/libexec/helmr/mkfs.ext4 ext4 formatter used for VM disks.
MKE2FS_CONFIG_PATH /usr/share/helmr/mke2fs.conf Configuration passed to the ext4 formatter.
IP_PATH ip iproute2 binary used for VM networking.
NFT_PATH nft nftables binary used for VM networking.
JAILER_CHROOT_DIR Derived from the Worker VM state directory. Base directory for jailer chroots.
JAILER_CGROUP_VERSION 2 Cgroup version passed to the jailer.

VM sizing, Worker capacity, disk budgeting, and concurrency use these settings:

Variable Default Purpose
VM_VCPUS 2 vCPUs assigned to each VM.
VM_MEMORY_MIB 2048 Memory assigned to each VM.
VM_SCRATCH_DISK_MIB 8192 Scratch disk assigned to each VM.
WORKER_CAPACITY_VCPUS VM_VCPUS Total vCPU capacity advertised by the Worker. It cannot be smaller than VM_VCPUS.
WORKER_CAPACITY_MEMORY_MIB VM_MEMORY_MIB Total memory capacity advertised by the Worker. It cannot be smaller than VM_MEMORY_MIB.
WORKER_DISK_MIB Total capacity of the Worker filesystem. Overrides the physical capacity used for disk budgeting.
WORKER_DISK_RESERVE_MIB 1024 Host disk space subtracted to form the physical disk budget.
WORKER_EXECUTION_SLOTS 1 Maximum concurrent executions admitted by the Worker.
VM_INIT_TIMEOUT 30s Timeout for Firecracker SDK initialization.
VM_HEALTH_TIMEOUT 30s Timeout for guest health convergence.

When both cache limits are 0, the Worker derives one shared cache budget and splits it two-thirds to the substrate cache and one-third to the artifact cache. When only one limit is 0, that cache receives its independently derived budget. The Worker advertises aggregate guest disk capacity after subtracting both the reserve and cache budgets from the configured or measured filesystem total.

The routed-network link and translation pools, resolver, and blocked CIDRs are required inputs listed above. The AWS Worker profile sets VM_HEALTH_TIMEOUT=300s for first-boot convergence on EC2; that is a provider profile value, not the Worker process default.