Configuration reference
Environment variables, Helm values, project YAML, and agent app YAML schema for Helix deployments.
Project YAML
Projects are defined in YAML. The full schema:
apiVersion: helix.ml/v1alpha1
kind: Project
metadata:
name: my-app # Used as the project identifier
spec:
description: "What this project is for"
repositories:
- url: "https://github.com/org/my-app"
branch: main
primary: true # The primary repo is cloned first and receives PRs
- url: "https://github.com/org/shared-lib"
branch: main
agent:
name: "My Agent"
runtime: claude_code # claude_code | goose_code | qwen_code | zed_agent
model: claude-sonnet-4-6 # omit for claude_code
provider: anthropic # anthropic | openai | helix | (any configured provider)
code_agent_credential_type: api_key # api_key (default) | subscription (Claude Code only)
# Goose-specific:
goose:
recipes:
- name: triage
path: .goose/recipes/triage.yamlAgent app YAML
Agent apps (called assistants in the YAML schema) configure conversational agents with skills, knowledge, and triggers. See Build an agent app for a walkthrough.
name: My Assistant
description: "What this agent app does"
assistants:
- name: Support
system_prompt: |
You are a helpful assistant.
temperature: 0.3
max_tokens: 4096
max_iterations: 10
agent_type: helix_agent # helix_basic | helix_agent
# --- helix_agent model configuration ---
# helix_agent uses four dedicated model roles instead of a single top-level
# provider/model. Do NOT set provider or model on a helix_agent assistant —
# the server silently clears those fields and they have no effect.
reasoning_model_provider: anthropic
reasoning_model: claude-sonnet-4-6
reasoning_model_effort: "" # optional: low | medium | high (default: provider default)
generation_model_provider: anthropic
generation_model: claude-haiku-4-5-20251001
small_reasoning_model_provider: anthropic
small_reasoning_model: claude-haiku-4-5-20251001
small_reasoning_model_effort: "" # optional
small_generation_model_provider: anthropic
small_generation_model: claude-haiku-4-5-20251001
# --- helix_basic model configuration (use instead of the block above) ---
# helix_basic uses a single provider/model pair:
# provider: anthropic
# model: claude-sonnet-4-6
# Skills
web_search:
enabled: true
max_results: 10
browser:
enabled: true
# Knowledge bases (RAG) — see guide-rag-knowledge
knowledge:
- name: my-docs
description: "Product documentation"
refresh_enabled: true
refresh_schedule: "0 */6 * * *"
rag_settings:
results_count: 4
chunk_size: 1024
chunk_overflow: 64
enable_vision: false # true to index images and scanned PDFs
source:
web:
urls:
- https://docs.example.com/
crawler:
enabled: true
max_depth: 2
max_pages: 200
readability: true
# API integrations (OpenAPI)
apis:
- name: My API
description: "Internal API"
url: https://api.example.com
schema: ./openapi.yaml
headers:
Authorization: Bearer ${MY_API_KEY}
# MCP servers — HTTP transport
mcps:
- name: My MCP Server
url: https://mcp.example.com/tools
headers:
Authorization: Bearer ${MCP_TOKEN}
# MCP servers — stdio transport (runs as subprocess)
# mcps:
# - name: Filesystem
# type: stdio
# cmd: npx
# args: ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
# Triggers — see guide-triggers
triggers:
- slack:
bot_token: ${SLACK_BOT_TOKEN}
channels:
- support
- teams:
tenant_id: ${TEAMS_TENANT_ID}
client_id: ${TEAMS_CLIENT_ID}
client_secret: ${TEAMS_CLIENT_SECRET}
- discord:
bot_token: ${DISCORD_BOT_TOKEN}
guild_id: "123456789"
- cron:
schedule: "0 9 * * 1-5"
input: "Generate daily summary"
- webhook: {} # Helix generates a unique URL
- azure_devops:
org_url: https://dev.azure.com/myorg
token: ${AZURE_DEVOPS_TOKEN}
events: [work_item_created, work_item_updated]
- crisp:
website_id: ${CRISP_WEBSITE_ID}
api_key: ${CRISP_API_KEY}
api_secret: ${CRISP_API_SECRET}Control plane environment variables
These are passed via controlplane.extraEnv in the Helm chart (or as environment variables in a non-Kubernetes deploy). See Linux & Kubernetes for how to set them.
Desktop streaming
| Variable | Default | Description |
|---|---|---|
HELIX_VIDEO_MODE | zerocopy | PipeWire capture: zerocopy (DMA-BUF→CUDA, fastest), native (DMA-BUF via GStreamer), shm (shared memory, most compatible). Use shm if browser shows endless reconnects. |
HELIX_ENCODER | auto | H.264 encoder: nvenc (NVIDIA), vaapi/vaapi-legacy (Intel/AMD), openh264/x264 (software). |
HELIX_GOP_SIZE | 120 | Group of Pictures size in frames (120 = 2s at 60fps). Lower = faster mid-stream join. |
HELIX_RENDER_NODE | unset | VA-API render device path (e.g. /dev/dri/renderD129). Set on multi-GPU hosts. Use SOFTWARE to disable VA-API. |
Control plane behaviour
| Variable | Default | Description |
|---|---|---|
HELIX_DISABLE_VERSION_CHECK | unset | Disable the upstream version-check ping at startup. Set to any non-empty value. |
HELIX_SKIP_AUTOMIGRATE | unset | Skip GORM AutoMigrate on startup. Only set if you run schema migrations out-of-band. |
HELIX_GITHUB_BASE_URL | https://github.com | Override for GitHub Enterprise Server. |
FRONTEND_URL | (from serverUrl) | Public URL of the Helix UI, injected into email links and OAuth callbacks. |
VHost TLS (web service hosting)
| Variable | Default | Description |
|---|---|---|
HELIX_VHOST_TLS_MODE | off | off (rely on upstream reverse proxy) or auto (embedded certmagic + Let's Encrypt). |
HELIX_VHOST_LETSENCRYPT_EMAIL | unset | ACME registration email. Required when HELIX_VHOST_TLS_MODE=auto. |
HELIX_VHOST_ACME_DNS_PROVIDER | "" | DNS-01 challenge provider. Empty = HTTP-01 + TLS-ALPN-01. Set to cloudflare when Helix is behind a Cloudflare proxy. |
HELIX_VHOST_CLOUDFLARE_API_TOKEN | unset | Cloudflare API token with Zone:Zone:Read + Zone:DNS:Edit. Required when HELIX_VHOST_ACME_DNS_PROVIDER=cloudflare. |
See Host a project as a web service for a full setup walkthrough.
Prompt queue & auto-wake
| Variable | Default | Description |
|---|---|---|
HELIX_MAX_PROMPT_QUEUE_RETRIES | 20 | Maximum number of times a failed prompt is retried by the queue before the selectors stop picking it up. Terminal conditions (wedged ACP threads) are crash-marked separately and excluded regardless of this cap. Increase in high-latency environments; decrease to surface failures sooner. |
HELIX_AUTO_WAKE_SESSION_WEDGE_THRESHOLD | 3 | Session-scoped circuit breaker for auto-wake. Once this many consecutive errored interactions occur since the session's last successful completion, auto-wake stops retrying. A genuine completion resets the count; the circuit never trips on a healthy session. |
Sandbox image registry
HELIX_SANDBOX_REGISTRY overrides the registry from which worker hosts pull the sandbox image. Useful for air-gapped deployments and for D3 autoscaling environments where the default GHCR pull can take several minutes across clouds.
| Variable | Default | Description |
|---|---|---|
HELIX_SANDBOX_REGISTRY | unset | Registry hostname for sandbox image pulls (default ghcr.io). Must be a bare hostname (e.g. internal-registry.corp, <acct>.dkr.ecr.us-east-1.amazonaws.com). Helix appends /helixml/helix-sandbox:<version> automatically — do not include an org path. Rejected at boot if the value contains internal whitespace, a URL scheme (https://...), a leading slash, or an embedded path segment. Trailing slashes are tolerated. For Runner Profile compose stacks, use HELIX_RUNNER_REGISTRY instead. |
Operator workflow: The image version is always derived from the Helix release — set the registry, never the tag. Before each Helix upgrade, pull helixml/helix-sandbox:<version> from ghcr.io, retag it for your registry, and push. Omitting this step leaves workers in a pull-retry loop with a clear diagnostic error.
Sandbox host (sandbox.extraEnv)
| Variable | Default | Description |
|---|---|---|
HELIX_SANDBOX_APT_MIRROR | unset | Override APT mirror for dev container bootstrapping. Useful in air-gapped environments. |
HELIX_SANDBOX_MAX_DEV_CONTAINERS | 20 | Maximum number of dev containers (spec-task sandboxes) a single Runner is allowed to host. Controls the max_sandboxes ceiling stored in the database for each Runner. Must be a positive integer — zero or negative is rejected at startup with an error. |
How HELIX_SANDBOX_MAX_DEV_CONTAINERS takes effect:
When Helix starts, BackfillSandboxMaxSandboxes updates all existing Runner rows to the configured value, not only newly registered Runners. This means changing the variable and restarting the control plane propagates the new ceiling to your entire fleet without requiring Runner re-registration.
What the ceiling controls and what it does not:
The autoscaler's demand-pressure path uses headroom = max_sandboxes − active_sandboxes to decide whether to provision additional Runners. HELIX_SANDBOX_MAX_DEV_CONTAINERS sets the max_sandboxes side of that equation.
The dispatcher (FindAvailableSandboxInstance) sorts Runners by active_sandboxes ASC when choosing where to place a new container, but does not hard-reject placement on a Runner that has reached its ceiling. Hard per-Runner rejection is a planned follow-up; for now, the ceiling shapes autoscaler headroom math rather than acting as a strict placement guard.
Disk-pressure admission control
The disk-pressure controller prevents ZFS pool exhaustion by enforcing two pool-free-percent thresholds. It runs inside the sandbox host (hydra) — the only component with ZFS access and dev-container lifecycle management.
| Variable | Default | Description |
|---|---|---|
HELIX_DISK_PRESSURE_ENABLED | true | Enable or disable disk-pressure admission control. |
HELIX_DISK_PRESSURE_REFUSE_FREE_PCT | 2 | Pool-free-percent threshold at-or-below which new dev containers are refused. CreateDevContainer returns a user-facing error and no container is started. |
HELIX_DISK_PRESSURE_STOP_FREE_PCT | 1 | Pool-free-percent threshold at-or-below which running dev containers are emergency-stopped. The background monitor gracefully stops all tracked containers so they stop writing. Containers are stopped, never removed — sessions remain resumable once space recovers. |
HELIX_DISK_PRESSURE_CHECK_INTERVAL | 30s | How often the background monitor checks pool free percent. |
Behaviour:
- Fail-open: if the ZFS pool cannot be measured (
zpool listerror, ZFS unavailable, unparsable output, or reported pool size zero), the controller takes no action — no starts are refused and no containers are stopped. A measurement failure never becomes a service outage. - Non-ZFS deployments: the controller is a no-op. No configuration change is required.
- Emergency stop snapshots the tracked container list under lock (no Docker calls while locked), is idempotent across monitor ticks, and is per-container best-effort — one container failure does not prevent the rest from being stopped.
Helm chart key reference
helix-controlplane
| Key | Description |
|---|---|
global.serverUrl | Public URL of the deployment. Must be set correctly — sandboxes use it to reach the control plane. |
controlplane.licenseKeyExistingSecret | Kubernetes secret name containing the license key |
controlplane.encryptionKeyExistingSecret | AES-256-GCM encryption key secret. Do not rotate after data is written. |
controlplane.runnerTokenExistingSecret | Shared token for sandbox↔control-plane auth |
controlplane.providers.* | LLM provider configuration (see Configure LLM providers) |
controlplane.extraEnv | Additional environment variables for the control plane pod |
controlplane.vhostTLS.enabled | false — set true to expose :443 (and optionally :80) on the Service and Deployment for embedded TLS termination. Requires HELIX_VHOST_TLS_MODE=auto. |
controlplane.vhostTLS.httpsPort | 443 — external HTTPS port. |
controlplane.vhostTLS.httpEnabled | true — set false when using DNS-01 (HELIX_VHOST_ACME_DNS_PROVIDER=cloudflare); the API does not bind :80 in DNS-01 mode. |
controlplane.vhostTLS.httpPort | 80 — external HTTP port for HTTP-01 challenge. Only used when httpEnabled=true. |
global.extraEnv | Environment variables for all pods (useful for proxy settings) |
helix-sandbox
| Key | Description |
|---|---|
sandbox.apiUrl | URL of the control plane, as seen from inside the cluster |
sandbox.runnerTokenExistingSecret | Must match controlplane.runnerTokenExistingSecret |
sandbox.extraEnv | Additional environment variables for the sandbox pod |
Full values-example.yaml files are in the Helix repository.