Configuration and environment variables¶
OpenAdapt is configured mostly through environment variables. The deterministic replay path needs none; they enable secrets, scrubbing, the optional model appliance, and effect verification.
Secrets¶
| Variable | Purpose |
|---|---|
OPENADAPT_FLOW_SECRET_<FIELD> |
Injects a secret field's value at replay. <FIELD> is the recorded field name, upper-cased. A field marked --secret (and any input[type=password]) is never persisted, so its value must be supplied here at replay, or the run fails fast. |
Privacy and scrubbing¶
| Variable | Purpose |
|---|---|
OPENADAPT_FLOW_SCRUB |
on runs the PHI/PII sanitizer over REPORT.md and console logs on the persist and log path. Missing dependencies, invalid config, and processing errors fail closed. Requires the privacy extra (pip install 'openadapt[privacy]') and the allowlisted spaCy model. |
The compiled bundle and report.json keep literal identifiers behind a
documented boundary and are not scrubbed by this flag; they are the identity
check and the audit trail. Sanitizer success is no proof that detectors found
every identifier, so review artifacts before egress. See
Deploy on-prem.
Encryption at rest¶
| Variable | Purpose |
|---|---|
OPENADAPT_BUNDLE_KEY |
Passphrase used by encrypted bundle saves/loads and durable checkpoints. run requires an encrypted bundle by default. |
Encryption is opt-in: inject the key and run openadapt flow seal SOURCE --out
DESTINATION; normal compile output is plaintext. The same key encrypts durable
checkpoints written during run/resume. OpenAdapt provides the AEAD mechanism,
not key custody, rotation, or recovery. See the security and deployment
review.
The on-prem VLM appliance¶
| Variable | Purpose |
|---|---|
OPENADAPT_FLOW_VLM_URL |
Points the runtime at an on-prem VLM appliance. Unset (the default): no model tiers exist and the ladder has no grounder rung. Set: the grounding rung, identity veto, and state verifier come online, all fail-safe to halt. |
The appliance is designed not to call external model services; enforce and test egress for the deployed image. See The on-prem VLM appliance.
Browser provisioning¶
Browser support has two intentionally separate layers. Install the Playwright
driver only for web workflows with pip install 'openadapt[browser]'. The
matching Chromium build downloads lazily on the first web action. Native
desktop, RDP, and Citrix commands neither import Playwright nor trigger a
browser download.
| Variable | Purpose |
|---|---|
OPENADAPT_FLOW_NO_AUTO_INSTALL |
Disables automatic browser provisioning. Set it when you manage the browser yourself (e.g. you ran playwright install chromium ahead of time in a controlled image). |
Hosted connectivity¶
| Variable | Purpose |
|---|---|
OPENADAPT_INGEST_TOKEN |
Token used by login, push, validate-hosted, and report-break when no --token is passed. The OS keychain is the next preferred token source. |
OPENADAPT_FLOW_DEPLOYMENT_KIND |
Default execution lane: cloud, byoc, or regulated. Independent of destination trust. |
OPENADAPT_FLOW_DESTINATION_KIND |
Destination trust class: openadapt-managed, customer-managed, or local. |
OPENADAPT_FLOW_TRUSTED_HOSTS |
Comma-separated exact HTTPS origins allowed for customer-managed upload. |
OPENADAPT_FLOW_AUTO_APPROVE_SANITIZED |
Administrator policy switch for fully covered, stable derivatives. Human review remains the default. |
OPENADAPT_FLOW_HOSTED_WORKFLOW_ID |
Opts a halting replay/run into the best-effort report-break hook for this workflow id. Off by default. |
OPENADAPT_FLOW_ORG_ID |
Optional organization id carried by the break-report hook. |
Every remote upload requires the approved immutable archive from the sanitation
pipeline. --attest-non-phi is deprecated and refused; a declaration is not a
privacy control. Customer-owned endpoints must be HTTPS and exact-origin
allowlisted. Unknown destinations fail closed.
These variables configure the client boundary for OpenAdapt Hosted. See Hosted browser execution.
The hosted control plane separately requires three server-side, comma-separated
allowlists: RUNTIME_VALIDATION_POLICIES, RUNTIME_VALIDATION_RISK_CLASSES, and
RUNTIME_VALIDATION_COMPILER_VERSIONS. The risk-class allowlist normally admits
one or both engine-derived values, low and consequential; the
compiler-version allowlist must name versions the runner actually deploys. Exact
membership is required. An operator attestation cannot introduce a new policy,
risk class, or compiler version.
Effect verification against a live system of record¶
| Variable | Purpose |
|---|---|
OPENEMR_FHIR_BASE_URL |
Base URL of a FHIR R4 API for the FhirEffectVerifier to read the system of record. |
OPENEMR_FHIR_TOKEN |
Bearer token for that FHIR API. |
These enable effect verification against a
real FHIR server. The verifier is selected in a
deployment config (effects.kind: fhir) or with the
--effects-kind / --effects-base-url flags on replay / run; these
variables supply its endpoint and credentials, keeping them out of the YAML.
The desktop in-session agent¶
| Variable | Purpose |
|---|---|
OAFLOW_AGENT_TOKEN |
Optional bearer token for the desktop in-session agent server. Its /execute_windows channel is remote code execution by contract; the server binds to loopback by default, and a token makes every request authenticate. Set it in any PHI/PII deployment that exposes the agent beyond loopback. |
The self-hosted phone portal¶
These govern where the attended decision portal listens and what URL it advertises to a paired phone. Use it when your organization provides the HTTPS/VPN/ZTNA path to the runner. The runner shows a QR code. The phone displays a one-use pairing code, and the operator approves that code on the runner.
| Variable | Default | Purpose |
|---|---|---|
OPENADAPT_PORTAL_INGRESS_MODE |
loopback |
loopback (this computer only) or customer_ingress (published through your own HTTPS/VPN ingress). |
OPENADAPT_PORTAL_PUBLIC_ORIGIN |
(unset) | The exact https:// origin your reverse proxy, VPN, or ZTNA hostname publishes for this runner. Required for customer_ingress. |
OPENADAPT_PORTAL_INGRESS_ACKNOWLEDGED |
false |
Explicit record that your organization operates that ingress and has reviewed protected evidence reaching phones. Required for customer_ingress. |
OPENADAPT_PORTAL_BIND_HOST |
(unset) | Optional literal IP address to bind, for when your ingress is not on this host. Left unset, the portal stays on 127.0.0.1 behind a same-host reverse proxy. |
OPENADAPT_PORTAL_PORT |
0 |
0 selects an ephemeral port. |
OPENADAPT_PORTAL_CONSOLE_PORT |
7863 |
Loopback port for the supervised attended console the portal relays to. |
Loopback is the default, and a phone cannot reach it
Unconfigured, the portal binds 127.0.0.1 and advertises a loopback URL.
That is a complete, working configuration on that computer — the pairing
screen says a phone cannot reach it rather than minting a link that fails on
your network. Publishing this surface to a phone is an explicit decision
you make by standing up trusted TLS in front of the runner. See
Deploy on-prem.
You do not have to. The hosted lane below reaches a phone from anywhere with nothing configured on your network; it carries less, and it says so.
Cloud phone access with no inbound ingress¶
The runner dials out to the control plane — no inbound port, no port forward, no certificate, no reverse proxy, no static address — so a phone reaches the queue from anywhere. In Cloud Needs attention, scan the QR code, sign in on the same Cloud origin, and optionally enable generic Web Push alerts. The QR code carries no session, runner credential, or decision authority. Turn the runner lane on in the deployment configuration, bound to the exact tenant and runner the control plane issued for this machine:
human_decisions:
remote:
enabled: true
tenant_id: <from the control plane>
runner_id: <from the control plane>
# context_tier: remote_closed_context # the default
| Variable | Purpose |
|---|---|
OPENADAPT_RUNNER_TOKEN |
The per-runner credential the control plane issued. The desktop app stores it in the operating-system keychain when you connect this computer, and passes it to the engine; set it by hand only for a headless runner. |
| Setting | Default | Purpose |
|---|---|---|
human_decisions.remote.enabled |
false |
Must be literally true. A truthy string does not enable it. |
human_decisions.remote.tenant_id |
(unset) | Required when enabled. |
human_decisions.remote.runner_id |
(unset) | Required when enabled. |
human_decisions.remote.context_tier |
remote_closed_context |
remote_closed_context (what broke, as closed enums and bounded integers) or remote_identifiers (identifiers and counts only). local_full is refused by name — protected evidence never leaves the runner. |
The execution profile applies its own ceiling, and the weaker of the two wins, so configuration cannot widen what a profile permits.
Every misconfiguration stops the console
A missing runner credential, a deployment that did not enable remote issuance, a read-only console, or a plaintext control-plane origin each refuse to start rather than run a console whose phone lane is silently absent. A lane that looks on and is not is worse than one that is plainly off.
Every widening step fails closed, and the portal does not start on an invalid combination rather than falling back to something more exposed:
- A wildcard bind address (
0.0.0.0,::, empty,*) is refused in every mode. There is no "bind everything for testing" switch. - The public origin must be a bare
https://origin — no plaintext, no path, no query, no embedded credentials, and no self-signed bypass. OPENADAPT_PORTAL_BIND_HOSTmust be a literal IP, not a hostname, and never an unspecified or multicast address.customer_ingressrequires both a public origin and the acknowledgement.- Setting a public origin or bind host while the mode is still
loopbackis an error, so a half-finished rollout cannot look configured when it is not.
Benchmark (agent arm only)¶
| Variable | Purpose |
|---|---|
ANTHROPIC_API_KEY |
Required only for the agent arm of openadapt flow benchmark. The compiled arm and all normal replay make no model calls and need no key. |
The agent arm costs money
Only the benchmark's agent arm calls a hosted model. Run it with cost caps. Nothing on the product's replay path requires an API key or incurs per-run cost.