---
title: Configuration reference
description: Every environment variable Hubzoid 1.0.1 reads, grouped by area, with its type, default and effect, and how the .env files are loaded.
canonical_url: https://hubzoid.com/docs/reference/configuration
last_updated: 2026-09-27
---

# Configuration reference

Every environment variable Hubzoid 1.0.1 reads, grouped by area, with its type, default and effect, and how the .env files are loaded.

Hubzoid is configured with environment variables. Most Hubs set a handful in `<hub>/.env`: the model, a bridge key and whatever surfaces they use. Everything else has a working default.

## How settings load

- **`<hub>/.env`** is loaded whenever a command builds or serves the Hub. Its values win over variables already set in your shell. A deployment that should take its values from the process environment instead (a systemd `EnvironmentFile`, a container platform) ships no `.env`.
- **`<hub>/restricted/.env`** is loaded next, also overriding. It holds secrets that [restricted tools](https://hubzoid.com/docs/guides/restrict-tools) read from the environment. The file tools refuse every path under `restricted/`, so the model cannot read these values.
- **Booleans** are on when set to `1`, `true` or `yes`, in any case. Most also accept `on`.
- **Numbers** that do not parse fall back to the default.
- **AWS Secrets Manager** is optional. A secret named by `AWS_SECRET_NAME`, `HUBZOID_HUB_SECRET_NAME` or `HUBZOID_RESTRICTED_SECRET_NAME` is read at start and wins over the file of its layer. See [configuration secrets](https://hubzoid.com/docs/reference/configuration#configuration-secrets).
- **In a gateway**, each bridge loads its own Hub's `.env`, and a Hub's `.env` stays with that Hub. Variables that describe the shared web chat, such as `OWUI_NATIVE_MCP`, `ENABLE_ADMIN_CHAT_ACCESS` or the provisioning credentials, belong in the environment of the `hubzoid gateway` process. Sign-in and web chat settings (`WEBUI_*`, `DEFAULT_USER_ROLE`, `ENABLE_SIGNUP`, OAuth settings and `HUBZOID_PUBLIC_URL`) are still taken from the Hubs' `.env` files when the gateway's own environment lacks them, and the gateway lists them at start. `WEBUI_NAME` in a Hub's `.env` no longer overrides `--name`.

`hubzoid init` writes a starter `.env` with a random bridge key and commented examples for each provider. `hubzoid doctor` checks the result. See [doctor](https://hubzoid.com/docs/reference/doctor).

## Models and reasoning

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `MODEL` | model id | `model:` in `AGENTS.md`, else `claude-local` | The Hub's model. `claude-local`, `claude-local/sonnet`, `claude-local/opus` and `claude-local/haiku` run on the Claude Agent SDK through the installed `claude` CLI (bare `claude-local` is Sonnet). `codex-local` and `codex-local/<model-id>` run on local Codex through the Codex CLI 0.147.0. Any other value is a LiteLLM id such as `openrouter/anthropic/claude-haiku-4.5`, `openai/gpt-4o-mini`, `anthropic/claude-haiku-4-5` or `azure/<deployment>`, run on the OpenAI Agents SDK. |
| `OPENROUTER_API_KEY` | secret | none | Key for `openrouter/` models. |
| `OPENAI_API_KEY` | secret | none | Key for `openai/` models. |
| `ANTHROPIC_API_KEY` | secret | none | Key for `anthropic/` models. The `claude` CLI also accepts it for `claude-local`. |
| `CLAUDE_CODE_OAUTH_TOKEN` | secret | none | Subscription token for `claude-local` on a server without an interactive `claude login`. Create it with `claude setup-token`. Usage draws on the Claude subscription. |
| `CODEX_HOME` | path | `~/.codex` | Where Hubzoid reads the file-backed Codex login, `auth.json`, for `codex-local`. The Codex CLI's own variable. |
| `JEV_OPENROUTER_API_KEY` | secret | none | Dedicated OpenRouter key for Jev decisions: `hub.call_jev` in workflows and the `call_jev` chat tool. There is no fallback to `OPENROUTER_API_KEY`, and the chat model never uses this key. The **Call Jev** capability shows "Jev key missing" in the Console until it is set. |
| `AZURE_API_KEY` | secret | none | Key for `azure/` models. |
| `AZURE_API_BASE` | URL | none | Azure OpenAI resource endpoint, for example `https://<resource>.openai.azure.com`. Required for `azure/` models. |
| `AZURE_API_VERSION` | string | LiteLLM's default | Azure REST API version, for example `2024-10-21`. |
| `REASONING_EFFORT` | `low`, `medium`, `high` | unset | OpenAI and Azure reasoning models receive it as their reasoning effort. On Claude it sets an extended thinking budget of 4,000, 12,000 or 24,000 tokens. Other values are ignored. |
| `SHOW_THINKING` | `off`, `indicator`, `full` | `indicator` | Claude backend only. `indicator` shows a thinking panel without the text, `full` streams the summarized reasoning, `off` shows nothing. `true` means `full` and `false` means `off`. |
| `SHOW_TOOLS` | `off`, `compact`, `full` | `compact` | How tool activity appears in replies. `compact` is a collapsible entry per call in the web chat and is hidden on Slack. `full` is an inline line on every surface. `off` shows nothing. `true` means `compact`, `false` means `off`, `inline` means `full`. |
| `HUBZOID_VISION` | boolean | `true` | Send uploaded images to the model as images. Set `false` for a text-only or cost-sensitive Hub. |
| `HUBZOID_VISION_MAX_EDGE` | integer | `1568` | Longest image edge, in pixels, before an image is sent. |
| `HUBZOID_VISION_MAX_IMAGES` | integer | `4` | Images expanded per turn. Older image references stay as text notes. |
| `HUBZOID_CACHE_TTL` | `1h`, `5m` | `1h` | Prompt cache lifetime for Anthropic-family models routed through LiteLLM (`anthropic/`, `openrouter/anthropic/`, Bedrock Claude). |
| `HUBZOID_DISABLE_PROMPT_CACHE` | boolean | `false` | Stop adding prompt cache markers to those requests. |
| `HUBZOID_EVAL_JUDGE_MODEL` | model id | the Hub's model | Model that grades eval cases. `hubzoid eval run --judge-model` wins. See [evals](https://hubzoid.com/docs/guides/evals). |

A scheduled task's `model:` frontmatter and `hubzoid schedule run --model` override the model for that run only. See [agents and models](https://hubzoid.com/docs/concepts/agents-and-models).

## Server, ports and links

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `PORT` | integer | `3080` | Public port of the web chat and the edge. `--port` wins. |
| `BRIDGE_PORT` | integer | `8000` | Bridge port. The bridge always binds `127.0.0.1`. `--bridge-port` wins. |
| `HUBZOID_HOST` | address | `127.0.0.1` | Interface the public port binds to. `0.0.0.0` listens on every interface. `--host` wins. |
| `BRIDGE_API_KEYS` | comma list | `dev` | Keys the bridge accepts as `Authorization: Bearer` on `/v1` and `/uploads`. The first key is the one the web chat sends. `dev` is public, so set a random key for any shared install. `hubzoid init` writes one. `dev` is never accepted on `/artifacts`. |
| `MODEL_LABEL` | string | slug of the `AGENTS.md` name | Model id reported by `/v1/models` and shown in the web chat. |
| `HUBZOID_PUBLIC_URL` | URL | `WEBUI_URL`, else `http://127.0.0.1:<BRIDGE_PORT>` | Public base URL used to build links: downloads from `write_artifact`, artifact viewer links and Console confirmation links. Set it behind a reverse proxy, for example `https://hub.example.com`. |
| `HUBZOID_MAX_UPLOAD_BYTES` | integer | `26214400` (25 MiB) | Per-file cap for attachments in chat requests and for `/uploads`. A larger file gets HTTP `413`. |
| `HUBZOID_ARTIFACT_SECRET` | secret | generated in `.hubzoid/artifact_secret` | Secret that signs download links. Set it only to share one secret across hosts serving the same Hub. Changing or deleting it revokes every issued link. |
| `HUBZOID_ARTIFACT_LINK_TTL` | seconds | `0` | How long a newly issued chat download link from `write_artifact` stays valid. `0` means links do not expire. |
| `HUB_LOG_LEVEL` | `info`, `debug`, `warning` | `info` | Log level of the bridge and edge. |
| `HUBZOID_DISABLE_EDGE` | boolean | `false` | Run without the edge. The web chat binds the public port directly, and bridge paths such as `/artifacts`, `/portal` and `/mcp` are not forwarded. |
| `HUBZOID_OWUI_PORT` | integer | `PORT` plus 40000 | Loopback port of the web chat behind the edge. |
| `HUBZOID_INBOUND_PORT` | integer | `8100` | Loopback port of the WhatsApp, Telegram and webhook receiver. Give each Hub its own value in a gateway. |
| `HUBZOID_HUB_SLUG` | string | slug of the Hub folder name | Path segment in `/webhooks/<slug>/`. Set it only when two Hubs in one gateway would otherwise get the same slug. |
| `HUBZOID_SESSION_ID` | string | random | Fixes the session id used for the `output/<session>/` folder. |

## Artifacts and email

These settings govern published artifacts, created with `hub.publish_artifact` or the markdown task tool `publish_artifact`, and email to the account a run acts as, sent with `hub.send_email` or `send_email`. See the [workflow API](https://hubzoid.com/docs/reference/workflow-api).

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `HUBZOID_ARTIFACT_MAX_BYTES` | integer | `52428800` (50 MiB) | Largest file a workflow may publish as an artifact. |
| `HUBZOID_ARTIFACT_LINK_DAYS` | integer | `7` | Default lifetime, in days, of an artifact's public link. Kept between 1 and 90. |
| `HUBZOID_ARTIFACT_ALLOW_ORIGINS` | comma list | none | HTTPS origins that published HTML artifacts may load scripts, styles, fonts and images from, for example `https://cdn.jsdelivr.net`. Unset, HTML artifacts make no network requests. |
| `HUBZOID_EMAIL_DELIVERY` | `smtp`, `preview` | `smtp` | `preview` writes each email to `<hub>/.hubzoid/outbox/<person>/` and reports that nothing was sent. |
| `HUBZOID_SMTP_HOST` | host | none | SMTP server. Required with `HUBZOID_SMTP_FROM` for `smtp` delivery. |
| `HUBZOID_SMTP_PORT` | integer | `587`, or `465` with `HUBZOID_SMTP_SSL` | SMTP port. |
| `HUBZOID_SMTP_USERNAME` | string | none | SMTP user name, when the server needs one. Credentials are sent only over TLS. |
| `HUBZOID_SMTP_PASSWORD` | secret | none | SMTP password. |
| `HUBZOID_SMTP_FROM` | email | none | Sender address. A single email address. |
| `HUBZOID_SMTP_STARTTLS` | boolean | `true` | Upgrade the connection with STARTTLS. |
| `HUBZOID_SMTP_SSL` | boolean | `false` | Use implicit TLS instead, usually on port 465. |
| `HUBZOID_SMTP_TIMEOUT` | seconds | `30` | Time allowed for each SMTP operation. |

SMTP delivery over TLS has not yet been verified against a real mail server for 1.0.1. Email always goes to the account the run acts as, and never to anyone else. A local or example account such as `admin@localhost` cannot receive it, so run the workflow as a real account or use `preview`. In a gateway, these settings can be set once for the deployment and overridden per Hub.

## Databases and deployment state

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `DATABASE_URL` | database URL | `sqlite:///<hub>/.hubzoid/hub.db` | Database for the Hub's own tables. A PostgreSQL URL here is also used for the operational store and the workflow engine unless the variables below say otherwise. PostgreSQL needs `pip install "hubzoid[postgres]"`. |
| `HUBZOID_OPERATIONAL_DB` | database URL | see below | Shared store for access grants, identities, audit records, usage and workflow state. |
| `HUBZOID_DBOS_DB` | database URL | see below | System database of the durable workflow engine. SQLite is always per Hub. PostgreSQL can be shared by several bridges. |
| `HUBZOID_DEPLOYMENT` | path | discovered from `<hub>/.hubzoid/deployment.json` | Explicit path to a gateway deployment manifest. |
| `OWUI_INTERNAL_URL` | URL | from the manifest, else `WEBUI_URL` | Server-to-server address of the web chat. The bridge uses it to verify Console sessions and read accounts. `hubzoid run` sets it for you. |
| `HUBZOID_OWUI_DB` | path | `<hub>/.openwebui-data/webui.db` | Web chat database the bridge reads for groups, API keys, uploads and per-user tool tokens. `hubzoid gateway` sets it to `<data-dir>/webui.db`. Bridges run with `--no-bridges` must set it themselves. |

The operational store resolves in this order: the registered gateway manifest, then `HUBZOID_OPERATIONAL_DB`, then `DATABASE_URL`, then the Hub's own database. The workflow engine resolves as: the manifest entry for the Hub, then `HUBZOID_DBOS_DB`, then `DATABASE_URL` when it is not SQLite, then `<hub>/.hubzoid/dbos.db`. When a manifest exists, a different `HUBZOID_OPERATIONAL_DB` or `HUBZOID_DBOS_DB` stops startup with an error instead of splitting the data. Change the gateway's configuration, not a single bridge.

## Chat surfaces

### Slack

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `SLACK_BOT_TOKEN` | secret | none | Bot user OAuth token (`xoxb-`). Required by the Slack adapter. |
| `SLACK_APP_TOKEN` | secret | none | App-level token (`xapp-`) with the `connections:write` scope, for Socket Mode. Required by the Slack adapter. |
| `SLACK_IDENTITY_MAPPING` | boolean | `false` | Resolve each sender's verified Slack email (needs the `users:read.email` scope) and apply the matching web chat account's groups. Emails match without regard to case. No match means anonymous. Restricted tools also need the Slack surface in `HUBZOID_RESTRICTED_SURFACES`. |

### WhatsApp and Telegram

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `WHATSAPP_VERIFY_TOKEN` | secret | none | Token checked on Meta's webhook verification request. |
| `WHATSAPP_APP_SECRET` | secret | none | App secret used to verify the `X-Hub-Signature-256` header on each delivery. |
| `WHATSAPP_TOKEN` | secret | none | Access token used to send replies. |
| `WHATSAPP_PHONE_NUMBER_ID` | string | none | Sending phone number id. All four WhatsApp variables are required. |
| `TELEGRAM_BOT_TOKEN` | secret | none | Bot token. |
| `TELEGRAM_WEBHOOK_SECRET` | secret | none | Checked against the `X-Telegram-Bot-Api-Secret-Token` header. Both Telegram variables are required. |
| `TELEGRAM_STREAM` | boolean | `true` | Edit the Telegram reply in place as it streams. |
| `INBOUND_STREAM_INTERVAL` | seconds | `1.0` | Minimum time between edits of the same Telegram message. Values below `0.8` are raised to `0.8`. |
| `INBOUND_HISTORY_MAX` | integer | `40` | Messages of history kept per WhatsApp or Telegram conversation. |
| `INBOUND_HISTORY_TTL_DAYS` | number | `0` | Drop conversation history older than this many days. `0` keeps it. |
| `INBOUND_MSG_VERIFY_PROMPT` | text | `Please tap the button below to verify your number.` | Fixed message asking a sender to verify. |
| `INBOUND_MSG_VERIFIED` | text | `You are verified. How can I help?` | Fixed message after verification. |
| `INBOUND_MSG_NOT_REGISTERED` | text | `This number is not registered for access.` | Fixed message for a number not in the roster. |
| `INBOUND_MSG_NOT_OWN_CONTACT` | text | `Please share your own number to verify.` | Fixed message when a sender shares someone else's contact. |
| `INBOUND_MSG_PLEASE_VERIFY` | text | `Please verify first. Tap the button below to share your number.` | Fixed message for an unverified sender. |
| `INBOUND_MSG_NO_RESPONSE` | text | `Sorry, I do not have a response for that. Please try again.` | Sent when a reply would otherwise be empty. |

### Generic webhook

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `WEBHOOK_INBOUND_SECRET` | secret | none | Shared secret. The webhook receiver is off without it. |
| `WEBHOOK_INBOUND_NAME` | string | `webhook` | Path segment of the endpoint, `/webhooks/<hub>/<name>`, and the inbox a task names in `on_webhook:`. |
| `WEBHOOK_INBOUND_HMAC` | boolean | `false` | Verify `X-Signature-256` or `X-Hub-Signature-256` as `sha256=` HMAC of the raw body instead of accepting the secret as a header. |

See [WhatsApp and Telegram](https://hubzoid.com/docs/chat/whatsapp-and-telegram), [Slack](https://hubzoid.com/docs/chat/slack) and [webhooks](https://hubzoid.com/docs/guides/webhooks).

## Access and identity

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `HUBZOID_RESTRICTED_SURFACES` | comma list | `owui,web,api,mcp,workflow` | The complete list of surfaces that may reach restricted tools. Setting it replaces the default, so include the defaults you still want, for example `owui,web,api,mcp,workflow,slack-dm`. `slack-dm` covers one-to-one Slack conversations. Add `whatsapp` or `telegram` to reach restricted tools and personal connections from those surfaces. Never add `slack-channel`, where one reply answers a shared thread under one person's identity. |
| `HUBZOID_PORTAL_DEV` | boolean | `false` | Development only. With `HUBZOID_PORTAL_DEV_USER`, the Console trusts that subject without a web chat session. Never set it on a shared or public deployment. |
| `HUBZOID_PORTAL_DEV_USER` | email | none | The subject trusted when `HUBZOID_PORTAL_DEV` is on. |
| `HUBZOID_LOCK_OWUI_ACCESS_UI` | boolean | `false` | Refuse browser writes to the web chat's group management through the edge, so access is managed only in the Console. |
| `HUBZOID_OWUI_LOCKED_PREFIXES` | comma list | `/api/v1/groups` | Web chat paths covered by that lock. |
| `HUBZOID_HIDE_OWUI_USERS` | boolean | on for a gateway first set up with Console accounts, off otherwise | Hide the web chat's own user management. Its Users page opens the Console's People page, its Admin Panel opens on Settings > Integrations, and browser writes to its account admin API are refused. When every agent is managed in the Console, its Groups page is hidden too. The default is recorded in the gateway's `deployment.json`, and existing deployments keep the Users page. Set it in the gateway's environment. |
| `HUBZOID_MANAGEMENT_TOOLS` | boolean | `false` | Give the Hub's agent the tools that propose access changes and new accounts (`my_management_scope`, `propose_access_change`, `propose_new_account`). Effective only on a Hub managed in the Console. A proposal applies only after the same manager confirms it there. |
| `HUBZOID_CHANGE_REQUEST_TTL` | seconds | `900` | How long a proposed change waits for confirmation in the Console. Kept between 60 and 86,400. |

See [identity and access](https://hubzoid.com/docs/concepts/identity-and-access) and [tools and connectors](https://hubzoid.com/docs/guides/tools-and-connectors).

## Schedules and workflows

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `HUBZOID_SCHEDULES` | boolean | `false` | Fire scheduled code workflows (`workflows/<name>/*.py`) in a standalone `hubzoid run`. `hubzoid gateway` turns it on for every bridge. Missed slots are reported, not replayed. Markdown tasks and scheduled evals do not need it. |
| `HUBZOID_DISABLE_SCHEDULE` | boolean | `false` | Stop markdown tasks (`schedule/*.md`) and scheduled evals from firing. |
| `HUBZOID_WORKFLOW_USER` | email | the owner recorded at setup on a Console-managed Hub, `admin@localhost` locally | The account scheduled code workflows and markdown tasks run as when they declare no `run_as`. A Hub's value (its secret, then its `.env`) wins over the deployment's. It must be an existing account that is not pending or blocked and, on a Console-managed Hub, holds **Use this agent**. |

Two workflow limits live in `workflows/settings.yaml` rather than the environment: `max_concurrent_workflows`, an optional cap on code workflows running at once in the Hub (no cap by default), and `agent_max_attempts`, how many times a failed `hub.call_agent` step is tried (1 by default, so no retry). See [workflows and schedules](https://hubzoid.com/docs/concepts/workflows-and-schedules).

## MCP

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `MCP_SERVER` | boolean | `false` | Serve the Hub's tools and knowledge over MCP at `/mcp` (at `/b/<hub>/mcp` in a gateway). The web chat then lets people create personal API keys, which work only as MCP credentials. |
| `MCP_ACCESS_GROUP` | string | none | For a Hub with group-based access: only members of this web chat group pass MCP authentication. On a Hub whose access is managed in the Console, the `use_hub` grant is the gate and this variable is not consulted. |
| `OWUI_NATIVE_MCP` | boolean | `false` | Use MCP servers that an admin registers in the web chat and each person connects with their own account. The bridge injects that person's token on their turns, on all three runtimes. On a Console-managed Hub each server also needs the person's `connector_<app>` capability. Needs a fixed `WEBUI_SECRET_KEY`. Gateway-wide in a gateway. |
| `HUBZOID_CONNECT_JOURNEY` | boolean | `false` | Give the agent the `connect_account` tool, which sends a person a personal link to connect an app from chat or WhatsApp. Uses the native MCP connections above. |
| `HUBZOID_CONNECT_TTL` | seconds | `600` | How long a connection link stays valid. Kept between 60 and 3,600. |

See [connect an assistant](https://hubzoid.com/docs/guides/connect-an-assistant) and [personal MCP connections](https://hubzoid.com/docs/guides/tools-and-connectors#per-user-mcp-servers).

## Tools and the shared browser

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `HTTP_ALLOWLIST` | comma list | none | Hostnames `http_get` may fetch. Subdomains of a listed host are allowed. Unset allows any host. |
| `HUBZOID_DISABLE_HTTP_GET` | boolean | `false` | Remove `http_get` from the tool registry. |
| `HUBZOID_DISABLE_WEB_SEARCH` | boolean | `false` | Remove `web_search` from the tool registry. |
| `HUBZOID_BROWSER` | boolean | `false` | Give the Hub one shared Playwright browser as MCP tools (`browser_navigate`, `browser_click`, `browser_snapshot` and the rest). |
| `HUBZOID_BROWSER_PORT` | integer | `8931` | Port of the browser sidecar Hubzoid starts itself. |
| `HUBZOID_BROWSER_MCP_URL` | URL | `http://localhost:<port>/mcp` | Connect to an already running Playwright MCP endpoint and start nothing. |
| `HUBZOID_BROWSER_CDP_URL` | URL | none | Attach the sidecar to a browser pool (browserless) for hard limits. Use the `ws://host:3000?token=...` form so the token survives. |
| `HUBZOID_BROWSER_CHANNEL` | string | `chromium` | Browser build for the sidecar. Keep `chromium` in containers. |
| `HUBZOID_BROWSER_MCP_VERSION` | string | `0.0.81` | Pinned `@playwright/mcp` version for the sidecar Hubzoid starts. `latest` floats deliberately. |
| `HUBZOID_BROWSER_MAX_RSS_MB` | integer | `0` | Without a pool, restart the browser when its memory passes this many MB. `0` turns the watchdog off. |
| `HUBZOID_BROWSER_CONCURRENT` | integer | `2` | Parallel browser slots in the pool. Read by `docker/browser-compose.yml`. |
| `HUBZOID_BROWSER_QUEUED` | integer | `5` | Requests that may wait before the pool rejects new ones. Read by the compose file. |
| `HUBZOID_BROWSER_MEMORY` | size | `2g` | Hard memory ceiling of the pool container. Read by the compose file. |
| `HUBZOID_BROWSER_TIMEOUT_MS` | milliseconds | `60000` | Pool timeout that reaps stuck sessions. Read by the compose file. |
| `HUBZOID_BROWSER_TOKEN` | secret | `hubzoid` | Token shared by the pool and the sidecar in the compose file. |
| `HUBZOID_BROWSER_MCP_IMAGE_TAG` | string | `v0.0.81` | Playwright MCP image tag in the compose file. |
| `HUBZOID_BROWSER_TIMEOUT` | seconds | `60` | No effect in 1.0.1. Hubzoid reads the value, but nothing uses it. Set the pool timeout with `HUBZOID_BROWSER_TIMEOUT_MS`. |

See [tools and connectors](https://hubzoid.com/docs/guides/tools-and-connectors#the-shared-browser) and [built-in tools](https://hubzoid.com/docs/reference/built-in-tools).

## Telemetry

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `HUBZOID_OTEL_ENDPOINT` | URL | none | OTLP/HTTP base URL for traces, for example a Langfuse `.../api/public/otel` endpoint. Unset turns tracing off. |
| `HUBZOID_OTEL_NORMALIZE` | boolean | `false` | `claude-local` only. The bridge receives the `claude` process's traces on a loopback route, renames token attributes to the `gen_ai.usage.*` names Langfuse maps, sets the person as `user.id`, and forwards them. No separate collector is needed. |
| `HUBZOID_OPENAI_TRACING` | boolean | `false` | OpenAI Agents backend only. Export runs, including prompts and tool data, to OpenAI's trace dashboard. Independent of `HUBZOID_OTEL_ENDPOINT`. |
| `OTEL_EXPORTER_OTLP_HEADERS` | `k=v,k=v` | none | Headers for the trace backend, such as `Authorization=Basic ...`. Also read back for eval pushes to Langfuse. |
| `OTEL_EXPORTER_OTLP_PROTOCOL` | string | `http/protobuf` | OTLP protocol for the `claude` process. |
| `OTEL_METRICS_EXPORTER` | string | `none` | Metrics exporter for the `claude` process. Set it only if you run a metrics backend. |
| `OTEL_LOGS_EXPORTER` | string | `none` | Logs exporter for the `claude` process. |
| `OTEL_RESOURCE_ATTRIBUTES` | `k=v,k=v` | none | Resource attributes for traces. On the OpenAI Agents backend Hubzoid adds `hubzoid.hub` to yours. On `claude-local` the `claude` process gets `hubzoid.user`, `hubzoid.hub`, `hubzoid.surface` and `user.id` for each turn. |
| `LANGFUSE_PUBLIC_KEY` | secret | none | With `LANGFUSE_SECRET_KEY` and `HUBZOID_OTEL_ENDPOINT`, eval runs are pushed to Langfuse as datasets with scores. |
| `LANGFUSE_SECRET_KEY` | secret | none | See `LANGFUSE_PUBLIC_KEY`. |

See [observability](https://hubzoid.com/docs/deploy/observability).

## Gateway

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `HUBZOID_GATEWAY_ADMIN_EMAIL` | email | none | With the password and `WEBUI_AUTH=true`, provision each Hub's model entry, description, suggestions, avatar and team group in the shared web chat at boot. |
| `HUBZOID_GATEWAY_ADMIN_PASSWORD` | secret | none | Password for that admin account. Both must be set. |
| `HUBZOID_GATEWAY_BRANDING` | Hub slug or path | see effect | The Hub whose `branding/` folder brands the shared web chat. Without it, `<data-dir>/branding/` is used when it holds files, then the first Hub's `branding/`. |
| `HUBZOID_GATEWAY_ALLOW_BYPASS` | boolean | `false` | Allow `BYPASS_MODEL_ACCESS_CONTROL` in a gateway, which shows every Hub to every signed-in person. |

See [gateway deployment](https://hubzoid.com/docs/deploy/gateway).

## Configuration secrets

Each configuration layer can also read an AWS Secrets Manager secret that holds a flat JSON object of settings. Nothing here is needed when you use files alone. With no secret named, Hubzoid makes no AWS call. This path has not yet been verified against AWS itself for 1.0.1.

| Variable | Layer | Where to set it | Effect |
| --- | --- | --- | --- |
| `AWS_SECRET_NAME` | Deployment | The gateway's environment, or a standalone Hub's `.env` or environment | Name or ARN of the deployment secret. The gateway records it in `deployment.json` so bridges started on their own find it. In a gateway, a Hub's `.env` naming it is ignored. |
| `AWS_REGION` | All | Beside the secret name | Region for every secret read. `AWS_DEFAULT_REGION` is the fallback, and an ARN carries its own region. |
| `HUBZOID_HUB_SECRET_NAME` | Hub | `<hub>/.env` only | A secret whose keys override `<hub>/.env` for this Hub. |
| `HUBZOID_RESTRICTED_SECRET_NAME` | Restricted | `<hub>/restricted/.env` only | A secret whose keys override `restricted/.env` for this Hub's restricted tools. |

- Secrets are read at start with boto3's normal credential chain: an instance or task role, `AWS_PROFILE`, or access keys in the environment.
- Within a layer the secret wins over the file. A standalone Hub applies its deployment secret after its `.env`. A Hub in a gateway takes only the bridge's share of the deployment secret, before its own `.env`.
- A secret may not set `AWS_*` keys, secret names or process control keys such as `PATH`, `LD_*` or `PYTHONPATH`. Values are strings, numbers or booleans.
- A secret that cannot be read stops the process at start with the secret name, the layer and the AWS error class, never a value.
- Values are read once. After a rotation, restart the processes that read the secret: the gateway and every bridge for the deployment secret, the Hub's bridge, inbound and Slack processes for a Hub secret, and the Hub's bridge for a restricted secret.
- `hubzoid doctor` reports each configured key's layer by name only, and whether each secret can be read. `--skip-secret-fetch` lists the secrets without calling AWS. See [doctor](https://hubzoid.com/docs/reference/doctor).

## Web chat and branding

These are Open WebUI settings that Hubzoid sets defaults for or reads itself. A value in `.env` wins over Hubzoid's default.

| Variable | Type | Default | Effect |
| --- | --- | --- | --- |
| `WEBUI_NAME` | string | the `name` in `AGENTS.md` | Name on the sign-in page, sidebar and chat title. |
| `HUBZOID_KEEP_OWUI_SUFFIX` | boolean | `false` | Keep Open WebUI's own branding even when the Hub has files in `branding/`. Open WebUI's license limits when its branding may be removed. See [branding](https://hubzoid.com/docs/reference/hub-files#branding-branding). |
| `RESPONSE_WATERMARK` | string | the Hub folder name, `hubzoid` in a gateway | Watermark on copied messages. |
| `WEBUI_AUTH` | boolean | `False` | Require sign-in to the web chat. Off is for local use only. |
| `WEBUI_SECRET_KEY` | secret | none | Required when `WEBUI_AUTH` is on. Use a random value of 32 or more characters, for example from `openssl rand -hex 32`. Also the key for per-user MCP tokens. |
| `WEBUI_URL` | URL | none | The web chat's public URL. Required behind a reverse proxy and whenever an OAuth client id is set. Also the fallback base for download, artifact and connection links. |
| `ENABLE_SIGNUP` | boolean | `False` | Public email sign-up in the web chat. Off, administrators add accounts in the Console. An explicit value in `.env` still wins. |
| `ENABLE_OAUTH_SIGNUP` | boolean | `False` | Create an account automatically on a first single sign-on. Off unless you opt in for an SSO onboarding deployment. |
| `OAUTH_MERGE_ACCOUNTS_BY_EMAIL` | boolean | Open WebUI's default | With Google sign-in configured, `true` lets Google sign in to an account created in the Console. **Google sign-in only** in the Console's Add user works only when it is `true`, and `hubzoid doctor` warns (`auth.google_merge`) when Google is configured without it. |
| `ENABLE_ADMIN_CHAT_ACCESS` | boolean | `False` | Let web chat admins open other people's chats. |
| `ENABLE_ADMIN_EXPORT` | boolean | `False` | Let web chat admins export other people's chats. |
| `BYPASS_MODEL_ACCESS_CONTROL` | boolean | `True` for one Hub, `False` in a gateway | Whether every signed-in person sees every model. A gateway forces it off unless `HUBZOID_GATEWAY_ALLOW_BYPASS` is set. |

Hubzoid also sets defaults for other Open WebUI settings that turn off features it does not use, with the same rule that `.env` wins. The full list is in [branding.md](https://github.com/hubzoid/hubzoid/blob/main/docs/branding.md). Sign-in providers and account setup are covered in [authentication](https://hubzoid.com/docs/deploy/authentication).

## Set by Hubzoid

Hubzoid sets these for its own child processes. You do not set them by hand.

| Variable | Set by | Purpose |
| --- | --- | --- |
| `HUBZOID_HUB_DIR` | `hubzoid run` | Tells the bridge which Hub to serve. |
| `HUBZOID_GATEWAY` | `hubzoid gateway` | Marks a bridge as part of a gateway, which also enables scheduled code workflows. |
| `HUBZOID_EDGE_DEFAULT`, `HUBZOID_EDGE_ROUTES` | `hubzoid run`, `hubzoid gateway` | The edge's upstream for the web chat and its table of forwarded path prefixes. |
| `HUBZOID_EDGE_PUBLIC_SCHEME` | `hubzoid run`, `hubzoid gateway` | `https` when the declared public URL is HTTPS, so the edge forwards `X-Forwarded-Proto: https` upstream. |
| `HUBZOID_WEBHOOK_EVENTS` | the markdown task runner | Newline-separated event files a webhook-triggered `run:` script owns for this run. |
| `HUBZOID_RUN_AS` | the markdown task runner | The account a `run:` script's run acts as. For information only. It grants the script nothing. |
| `HUBZOID_DEPLOYMENT_SECRET_INHERITED` | `hubzoid gateway` | Tells a bridge the gateway has already read the deployment secret for it. |

## Next steps

- [Hub files](https://hubzoid.com/docs/reference/hub-files): What each file and folder in a Hub does.
- [CLI reference](https://hubzoid.com/docs/reference/cli): Commands, arguments and options.
- [Doctor checks](https://hubzoid.com/docs/reference/doctor): Checks that read this configuration and what to fix.
- [Security model](https://hubzoid.com/docs/deploy/security-model): How keys, ports and access fit together in a deployment.
