# Configuration reference

> Every environment variable that the TulipFarm services and the self-hosted stack read, grouped by area, with services, requirement, and defaults.

Source: https://tulipfarm.ai/docs/self-hosting/configuration-reference/

This reference is generated from the settings registry in
[`packages/config/src/settings.ts`](https://github.com/TulipFarm/tulipfarm/blob/main/packages/config/src/settings.ts) with `pnpm config:docs`.
Do not edit the tables by hand. For how to supply these values, see
[Self-hosting configuration](https://tulipfarm.ai/docs/self-hosting/configuration/index.md) and
[Secret stores](https://tulipfarm.ai/docs/self-hosting/secrets/index.md).

Services are the application processes that read each variable. Required values:
**Yes** always, **Production** when `NODE_ENV=production`, **Conditional** when the
related feature is configured, and **No** when a default applies or the feature stays
off. Generated variables are written by `self-host:setup`. Every variable marked
secret also accepts `<NAME>_FILE`; see [Secret files](https://tulipfarm.ai/docs/self-hosting/configuration/index.md#secret-files).

The PostHog project token setting is not part of open-source TulipFarm and is not
listed. Self-hosted installs send no product analytics to TulipFarm.

### Self-hosted stack

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `TULIPFARM_PUBLIC_URL` | Compose: api, web build | Yes | No |  | Public HTTPS origin, such as `https://tulipfarm.example.com`. |
| `TULIPFARM_SITE_ADDRESS` | Compose: web | Yes | No |  | Caddy site: a domain for automatic HTTPS, or `:80` behind another proxy. |
| `TULIPFARM_RELEASE_VERSION` | Compose: image builds | Yes | No |  | `YYYY.M.D.N`, a valid date. |
| `TULIPFARM_RELEASE_COMMIT` | Compose: image builds | Yes | No |  | Full 40-character source commit. |
| `POSTGRES_PASSWORD` | Compose: postgres, setup | Yes | Yes |  | PostgreSQL superuser password; use URL-safe characters. |
| `OBJECT_STORAGE_ACCESS_KEY_ID` | Compose: object-storage, setup | Yes | No |  | Bundled object-storage access key. |
| `OBJECT_STORAGE_SECRET_ACCESS_KEY` | Compose: object-storage, setup | Yes | Yes |  | Bundled object-storage secret key. |
| `TULIPFARM_HTTP_PORT` | Compose: web | No | No | `80` | Host HTTP port. |
| `TULIPFARM_HTTPS_PORT` | Compose: web | No | No | `443` | Host HTTPS port. |
| `TULIPFARM_SUPPORT_EMAIL` | Compose: web build | No | No |  | Support address on the Help page (web `VITE_SUPPORT_EMAIL`). Unset hides the contact section. |
| `COMPOSE_PROFILES` | Compose: docker compose | No | No |  | Compose profiles to start. `temporal` runs the bundled Temporal server, UI, schema and namespace jobs; omit it when TEMPORAL_ADDRESS points at your own Temporal. |
| `TEMPORAL_UI_PORT` | Compose: temporal-ui | No | No | `8233` | Loopback port for the bundled Temporal UI. |
| `TEMPORAL_HISTORY_SHARDS` | Compose: temporal | No | No | `128` | Bundled Temporal history shard count. You cannot change it after first start. |

### Runtime

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `NODE_ENV` | api, worker, storage-worker, snippet-broker, database | No | No |  | `production` enables production checks and fallbacks. Images set it. |
| `HOST` | api, snippet-broker | No | No | `127.0.0.1` | Listen address. |
| `PORT` | api, snippet-broker | No | No | `3001 (api), 8090 (snippet-broker)` | Listen port. |
| `API_PROXY_MODE` | api | No | No | `direct` | `direct`, `reverse-proxy`, or `azure-container-apps`: which proxy headers to trust. |
| `TEMPORAL_UI_URL` | api | No | No | `http://127.0.0.1:8233` | Temporal UI URL probed by the API health check. Empty skips the probe. Self-host defaults to the bundled `temporal-ui`. |
| `TULIPFARM_EXTENSIONS` | api, worker, storage-worker | No | No |  | Comma-separated extension modules loaded at startup: package names (resolved from the app) or paths. Unset runs with no extensions. See packages/extensions/README.md. |

### Public origins

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `BETTER_AUTH_URL` | api | Production | No |  | Public API origin used for auth callbacks and as the Workspace MCP OAuth client ID and redirect origin. |
| `WEB_ORIGIN` | api, worker | Production | No |  | Public web app origin. |
| `WEBSITE_ORIGIN` | api | No | No |  | Marketing website origin allowed by CORS. Defaults to WEB_ORIGIN in production. |
| `PUBLIC_GUIDE_ORIGINS` | api | No | No | `http://localhost:5100,http://127.0.0.1:5100` | Comma-separated origins allowed to call the public guide API. |
| `PUBLIC_WEB_ENDPOINT` | api, worker, database | No | No |  | Origin (no path or credentials) of a keyless Firecrawl-compatible API used by the agent `web.search` and `web.fetch` tools: `POST /v2/search`, `POST /v2/scrape`. Unset turns public web retrieval off; the tools then report results as unavailable. When set, the API health check needs `GET /health` to return 2xx, and `pnpm dev:setup` copies an exported value into the worker env. The endpoint fetches URLs that agents choose, so it must not be able to reach your internal network. |

### Database

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `DATABASE_URL` (generated) | api, database | Production | Yes |  | Application PostgreSQL connection URL. |
| `EMAIL_DELIVERY_DATABASE_URL` (generated) | worker | Production | Yes |  | Least-privilege login that drains the email delivery queue. |
| `RECOMMENDATION_DATABASE_URL` | api, worker | Conditional | Yes |  | Login used by the recommendation sweep. |

### Workspace storage

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `WORKSPACE_STORAGE_CAPABILITY` (generated) | api, worker, storage-worker, database | No | No | `disabled` | `isolated-v1` stores each workspace in its own database; `disabled` turns it off. |
| `WORKSPACE_DATABASE_ENDPOINT` (generated) | storage-worker | Conditional | No |  | Credential-free PostgreSQL URL where workspace databases live. |
| `WORKSPACE_PROVISIONING_DATABASE_URL` (generated) | storage-worker, database | Conditional | Yes |  | Login that creates workspace databases. |
| `WORKSPACE_MIGRATION_REGISTRY_DATABASE_URL` (generated) | storage-worker, database | Conditional | Yes |  | Login that records workspace migrations. |
| `WORKSPACE_AUTHORING_DATABASE_URL` (generated) | worker, storage-worker, database | Conditional | Yes |  | Login that reads workspace table definitions for authoring. |
| `WORKSPACE_CONFIRMATION_REGISTRY_DATABASE_URL` (generated) | api, database | Conditional | Yes |  | Login that records table-change confirmations. |
| `WORKSPACE_DATABASE_CONNECTION_BUDGET` | api, worker, storage-worker, database | No | No | `120` | Connections available to all workspace databases. |
| `WORKSPACE_RUNTIME_REPLICAS` | api, worker, storage-worker, database | No | No | `4` | Runtime replicas that share the connection budget. |

### Encryption keys

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `WORKSPACE_RUNTIME_KEY_ID` (generated) | api, worker, storage-worker | Production | No |  | Current key ID for workspace database runtime credentials. Stored with each ciphertext. |
| `WORKSPACE_RUNTIME_KEY` (generated) | api, worker, storage-worker | Production | Yes |  | Current AES-256-GCM key for workspace database runtime credentials: 64 hexadecimal characters. |
| `WORKSPACE_RUNTIME_PREVIOUS_KEYS` (generated) | api, worker, storage-worker | No | Yes |  | JSON map of retired key IDs to keys for workspace database runtime credentials. Used only to decrypt. |
| `WORKSPACE_CONFIRMATION_KEY_ID` (generated) | api, storage-worker | Production | No |  | Current key ID for table-confirmation credentials. Stored with each ciphertext. |
| `WORKSPACE_CONFIRMATION_KEY` (generated) | api, storage-worker | Production | Yes |  | Current AES-256-GCM key for table-confirmation credentials: 64 hexadecimal characters. |
| `WORKSPACE_CONFIRMATION_PREVIOUS_KEYS` (generated) | api, storage-worker | No | Yes |  | JSON map of retired key IDs to keys for table-confirmation credentials. Used only to decrypt. |
| `WORKSPACE_MIGRATION_KEY_ID` (generated) | storage-worker | Production | No |  | Current key ID for workspace migration credentials. Stored with each ciphertext. |
| `WORKSPACE_MIGRATION_KEY` (generated) | storage-worker | Production | Yes |  | Current AES-256-GCM key for workspace migration credentials: 64 hexadecimal characters. |
| `WORKSPACE_MIGRATION_PREVIOUS_KEYS` (generated) | storage-worker | No | Yes |  | JSON map of retired key IDs to keys for workspace migration credentials. Used only to decrypt. |
| `EMAIL_DELIVERY_KEY_ID` (generated) | api, worker, storage-worker | Production | No |  | Current key ID for queued sign-in links and invitations. Stored with each ciphertext. |
| `EMAIL_DELIVERY_KEY` (generated) | api, worker, storage-worker | Production | Yes |  | Current AES-256-GCM key for queued sign-in links and invitations: 64 hexadecimal characters. |
| `EMAIL_DELIVERY_PREVIOUS_KEYS` (generated) | api, worker, storage-worker | No | Yes |  | JSON map of retired key IDs to keys for queued sign-in links and invitations. Used only to decrypt. |
| `INTEGRATION_CREDENTIAL_KEY_ID` (generated) | api, worker, storage-worker | Production | No |  | Current key ID for connected-integration tokens. Stored with each ciphertext. |
| `INTEGRATION_CREDENTIAL_KEY` (generated) | api, worker, storage-worker | Production | Yes |  | Current AES-256-GCM key for connected-integration tokens: 64 hexadecimal characters. |
| `INTEGRATION_CREDENTIAL_PREVIOUS_KEYS` (generated) | api, worker, storage-worker | No | Yes |  | JSON map of retired key IDs to keys for connected-integration tokens. Used only to decrypt. |
| `SLACK_CREDENTIAL_KEYS` | api, worker | Conditional | Yes |  | Slack token keyring JSON: `{"activeKeyId":"v1","keys":{"v1":"<64 hex>"}}`. |

### Object storage

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `R2_ENDPOINT` (generated) | api, worker, storage-worker | No | No |  | S3-compatible endpoint for agent soul files. Unset uses the hosted Cloudflare R2 account. |
| `R2_SOUL_BUCKET` (generated) | api, worker, storage-worker | No | No | `tulipfarm-cloud-soul-<environment>` | Bucket for agent soul files. |
| `R2_ACCESS_KEY_ID` (generated) | api, worker, storage-worker | Production | No |  | Read-write object-storage access key. |
| `R2_SECRET_ACCESS_KEY` (generated) | api, worker, storage-worker | Production | Yes |  | Read-write object-storage secret key. |
| `R2_SOUL_READ_ACCESS_KEY_ID` (generated) | api, worker, storage-worker | Production | No |  | Read-only object-storage access key. |
| `R2_SOUL_READ_SECRET_ACCESS_KEY` (generated) | api, worker, storage-worker | Production | Yes |  | Read-only object-storage secret key. |
| `CHAT_R2_ACCOUNT_ID` | api, worker | Conditional | No |  | Cloudflare account for chat attachments. Unset disables attachment storage. |
| `CHAT_R2_BUCKET` | api, worker | Conditional | No |  | Bucket for chat attachments. |
| `CHAT_R2_ACCESS_KEY_ID` | api, worker | Conditional | No |  | Chat attachment access key. |
| `CHAT_R2_SECRET_ACCESS_KEY` | api, worker | Conditional | Yes |  | Chat attachment secret key. |

### Temporal

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `TEMPORAL_ADDRESS` | api, worker, storage-worker, database | No | No | `127.0.0.1:7233` | Temporal frontend address (`host:port`). Self-host defaults to the bundled `temporal:7233`; set it when COMPOSE_PROFILES omits `temporal`. No TLS or API-key client options yet. |
| `TEMPORAL_NAMESPACE` | api, worker, storage-worker, database | No | No | `default` | Temporal namespace. The bundled namespace job creates it. |
| `TEMPORAL_TASK_QUEUE` | api, worker | No | No | `tulipfarm` | Task queue for the ordinary worker. |
| `TEMPORAL_STORAGE_TASK_QUEUE` | api, storage-worker | No | No | `tulipfarm-storage-v1` | Task queue for the storage worker. |

### Models

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `ANTHROPIC_API_KEY` | api, worker, storage-worker | Conditional | Yes |  | Anthropic API key for Claude model families. |
| `OPENAI_API_KEY` | api, worker, storage-worker | Conditional | Yes |  | OpenAI API key for GPT model families on api.openai.com. Azure Foundry serves them instead when `AZURE_FOUNDRY_API_KEY` is set. |
| `XAI_API_KEY` | api, worker, storage-worker | Conditional | Yes |  | xAI API key for Grok model families on api.x.ai. Azure Foundry serves them instead when `AZURE_FOUNDRY_API_KEY` is set. |
| `GEMINI_API_KEY` | api, worker, storage-worker | Conditional | Yes |  | Google Gemini API key for Gemini model families. |
| `ANTHROPIC_BASE_URL` | api, worker, storage-worker | No | No | `https://api.anthropic.com` | Replaces the Anthropic API origin, for a gateway or regional endpoint; `/v1/messages` is appended, so leave `/v1` out. Its host must be in `MODEL_ENDPOINT_HOSTS`. |
| `OPENAI_BASE_URL` | api, worker, storage-worker | No | No | `https://api.openai.com/v1` | Replaces the OpenAI API base URL, for a gateway such as LiteLLM or Portkey. A URL without a path gets `/v1`; one with a path is the API base. Its host must be in `MODEL_ENDPOINT_HOSTS`. |
| `XAI_BASE_URL` | api, worker, storage-worker | No | No | `https://api.x.ai/v1` | Replaces the xAI API base URL, with the same rules as `OPENAI_BASE_URL`. Its host must be in `MODEL_ENDPOINT_HOSTS`. |
| `GEMINI_BASE_URL` | api, worker, storage-worker | No | No | `https://generativelanguage.googleapis.com` | Replaces the Gemini API origin; `/v1beta/models/...` is appended, so leave `/v1beta` out. Its host must be in `MODEL_ENDPOINT_HOSTS`. |
| `MODEL_ENDPOINT_HOSTS` | api, worker, storage-worker | Conditional | No |  | Comma-separated host names (no scheme, port or path; exact match, no wildcards) that model credentials may be sent to, besides the built-in provider APIs and Azure Foundry resource hosts. Required for every `*_BASE_URL` on another host and every `openai-compatible` catalog endpoint. Endpoints use https; http is allowed only for localhost, 127.0.0.1 and ::1 outside production. URLs must not contain credentials. |
| `MODEL_FAMILIES` | api, worker, storage-worker | No | No |  | Comma-separated model families to enable. Unset enables every family a configured provider key serves. See [model configuration](https://tulipfarm.ai/docs/self-hosting/models/index.md). |
| `MODEL_DEFAULT_FAMILY` | api, worker, storage-worker | No | No |  | Default model family for new agents and agent-instruction improvements. Falls back to the catalog's `default-chat` role. |
| `MODEL_CATALOG_FILE` | api, worker | No | No |  | Path to a JSON model catalog (`{ "families": [...], "models": [...] }`, the shape of the shipped `model-families.json` entries and `model-pricing.json` models). A model entry with a shipped ID sets your own prices; a family with `"pricing": "unmetered"` has models without rates that cost zero. A family's `roles` (`default-chat`, `title`, `compaction`, `review`, `plan`, `heartbeat`, `public-guide`) make it the default for those features. Startup fails naming any invalid entry. Set this or `MODEL_CATALOG`, not both. |
| `MODEL_CATALOG` | api, worker | No | No |  | Inline JSON model catalog, the same shape as the `MODEL_CATALOG_FILE` contents. |
| `MODEL_CATALOG_MODE` | api, worker | No | No | `extend` | `extend` adds the operator catalog to the shipped one; an entry with a shipped ID replaces it. `replace` uses only the operator catalog. `MODEL_FAMILIES` still selects the enabled families. |
| `AZURE_FOUNDRY_ENDPOINT` | api, worker, storage-worker | Conditional | No |  | Azure Foundry endpoint for Azure model families and knowledge embeddings. Required with `AZURE_FOUNDRY_API_KEY`; there is no built-in endpoint. |
| `AZURE_FOUNDRY_API_KEY` | api, worker, storage-worker | Conditional | Yes |  | Azure Foundry API key for Azure model families, and for GPT and Grok families when it is set. |
| `CHAT_TITLE_MODEL_FAMILY` | worker | No | No |  | Model family that titles chats. Outside `MODEL_FAMILIES`, the chat model titles the chat. Defaults to the first `MODEL_FAMILIES` family with the catalog role `title`. |
| `SKILL_REVIEW_MODEL_FAMILY` | worker | No | No |  | Model family that safety-reviews imported skills. Must be in `MODEL_FAMILIES`. Defaults to the first `MODEL_FAMILIES` family with the catalog role `review`. |
| `PLAN_SPECIALIST_MODEL_FAMILY` | worker | No | No |  | Model family for the plan specialist. Must be in `MODEL_FAMILIES`. Defaults to the first `MODEL_FAMILIES` family with the catalog role `plan`. |
| `GMAIL_HEARTBEAT_MODEL_FAMILY` | worker | No | No |  | Model family that triages Gmail heartbeats. Must be in `MODEL_FAMILIES`. Defaults to the first `MODEL_FAMILIES` family with the catalog role `heartbeat`. |
| `PUBLIC_GUIDE_MODEL_FAMILY` | api | No | No |  | Model family that answers the public guide; it needs an Azure chat-completions route. Defaults to the first `MODEL_FAMILIES` family with the catalog role `public-guide`. |
| `TABLE_SEARCH_MODEL_FAMILY` | api, worker, storage-worker | No | No |  | Model family that translates table searches. Unset disables model translation. |
| `TABLE_SEARCH_TRANSLATOR` | api, worker, storage-worker | No | No | `model` | `model`, or `fake` for local tests only. |
| `KNOWLEDGE_EMBEDDINGS_ENABLED` | api, worker, storage-worker | No | No | `false` | `true` embeds knowledge with the configured embeddings provider. |
| `KNOWLEDGE_EMBEDDINGS_PROVIDER` | api, worker, storage-worker | No | No | `azure-foundry` | `azure-foundry` or `openai-compatible`. Either must serve `text-embedding-3-large` at 1536 dimensions. See [embedding providers](https://tulipfarm.ai/docs/self-hosting/models/index.md#embedding-providers). |
| `KNOWLEDGE_EMBEDDINGS_BASE_URL` | api, worker, storage-worker | Conditional | No |  | OpenAI-compatible base URL; `embeddings` is appended. HTTPS, or HTTP on loopback only. |
| `KNOWLEDGE_EMBEDDINGS_API_KEY` | api, worker, storage-worker | Conditional | Yes |  | API key for the OpenAI-compatible embeddings provider. |
| `KNOWLEDGE_EMBEDDINGS_MODEL` | api, worker, storage-worker | No | No |  | Model or deployment name sent to the provider. Defaults to the stored profile model. |
| `KNOWLEDGE_EMBEDDINGS_DIMENSIONS` | api, worker, storage-worker | No | No | `1536` | Must equal 1536 when set. |

### Sign-in

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `BETTER_AUTH_SECRET` (generated) | api | Production | Yes |  | Session signing secret. Do not change it after first start. |
| `GOOGLE_CLIENT_ID` | api | Conditional | No |  | Google sign-in client ID. |
| `GOOGLE_CLIENT_SECRET` | api | Conditional | Yes |  | Google sign-in client secret. |
| `TURNSTILE_SITE_KEY` | api | No | No |  | Cloudflare Turnstile site key for sign-in. Unset disables the challenge. |
| `TURNSTILE_SECRET_KEY` | api | No | Yes |  | Cloudflare Turnstile secret key. Set together with TURNSTILE_SITE_KEY. |
| `AUTH_EMAIL_PASSWORD` | api | No | No | `false` | `true` adds email and password sign-in next to email links and Google, for instances without an email transport. Without one, an admin runs `pnpm auth:reset-password <email>` for a reset link. See [password sign-in](https://tulipfarm.ai/docs/self-hosting/sign-in/index.md#password-sign-in). |

### Email

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `ACS_CONNECTION_STRING` | api, worker | Conditional | Yes |  | Azure Communication Services connection string for email sign-in and invitations. |
| `ACS_SENDER_ADDRESS` | worker | Conditional | No |  | Verified sender address for email. |
| `EMAIL_PROVIDER` | api, worker | No | No |  | `acs` or `smtp`. Unset uses ACS when `ACS_CONNECTION_STRING` is set, otherwise SMTP when `SMTP_HOST` is set. Any email setting disables local dev sign-in. See [email transports](https://tulipfarm.ai/docs/self-hosting/email/index.md#choose-a-transport). |
| `SMTP_HOST` | api, worker | Conditional | No |  | SMTP server host name. |
| `SMTP_PORT` | worker | No | No |  | Defaults to `465` with `SMTP_SECURE=true`, otherwise `587`. |
| `SMTP_SECURE` | worker | No | No |  | `true` for implicit TLS. Defaults to `true` only on port 465. |
| `SMTP_REQUIRE_TLS` | worker | No | No | `true` | Require STARTTLS without implicit TLS. Set `false` only for a trusted local relay. |
| `SMTP_USER` | worker | No | No |  | SMTP user name. Set with `SMTP_PASSWORD`. |
| `SMTP_PASSWORD` | worker | No | Yes |  | SMTP password. Set with `SMTP_USER`. |
| `SMTP_FROM_ADDRESS` | worker | Conditional | No |  | Sender address, for example `noreply@example.com`. |

### GitHub

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `GITHUB_OAUTH_CLIENT_ID` | api, worker, storage-worker | Conditional | No |  | GitHub OAuth client ID. Unset disables GitHub. |
| `GITHUB_OAUTH_CLIENT_SECRET` | api, worker, storage-worker | Conditional | Yes |  | GitHub OAuth client secret. |
| `GITHUB_OAUTH_REDIRECT_URI` | api, worker, storage-worker | Conditional | No |  | GitHub OAuth callback URL registered with the provider. |
| `GITHUB_OAUTH_SCOPES` | api, worker, storage-worker | Conditional | No |  | Space-separated GitHub OAuth scopes. |
| `GITHUB_MCP_READ_BINDINGS` | api, worker, storage-worker | No | No |  | JSON list of trusted GitHub MCP read operations and contract digests. |
| `GITHUB_MCP_WRITE_BINDINGS` | api, worker, storage-worker | No | No |  | JSON list of trusted GitHub MCP write operations and contract digests. |

### Google Workspace

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `GOOGLE_WORKSPACE_CLIENT_ID` | api, worker, storage-worker | Conditional | No |  | Google Workspace OAuth client ID. Unset disables Google Workspace. |
| `GOOGLE_WORKSPACE_CLIENT_SECRET` | api, worker, storage-worker | Conditional | Yes |  | Google Workspace OAuth client secret. |
| `GOOGLE_WORKSPACE_REDIRECT_URI` | api, worker, storage-worker | Conditional | No |  | Google Workspace OAuth callback URL registered with the provider. |

### Atlassian

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `ATLASSIAN_MCP_CLIENT_ID` | api, worker | Conditional | No |  | Atlassian MCP OAuth client ID. Unset disables Atlassian MCP. |
| `ATLASSIAN_MCP_CLIENT_SECRET` | api, worker | Conditional | Yes |  | Atlassian MCP OAuth client secret. |
| `ATLASSIAN_MCP_REDIRECT_URI` | api, worker | Conditional | No |  | Atlassian MCP OAuth callback URL registered with the provider. |
| `ATLASSIAN_MCP_SCOPES` | api, worker | Conditional | No |  | Space-separated Atlassian MCP OAuth scopes. |
| `ATLASSIAN_REST_CLIENT_ID` | api, worker | Conditional | No |  | Atlassian REST OAuth client ID. Unset disables Atlassian REST. |
| `ATLASSIAN_REST_CLIENT_SECRET` | api, worker | Conditional | Yes |  | Atlassian REST OAuth client secret. |
| `ATLASSIAN_REST_REDIRECT_URI` | api, worker | Conditional | No |  | Atlassian REST OAuth callback URL registered with the provider. |
| `ATLASSIAN_REST_SCOPES` | api, worker | Conditional | No |  | Space-separated Atlassian REST OAuth scopes. |
| `TRELLO_CLIENT_ID` | api, worker | Conditional | No |  | Trello OAuth client ID. Unset disables Trello. |
| `TRELLO_CLIENT_SECRET` | api, worker | Conditional | Yes |  | Trello OAuth client secret. |
| `TRELLO_REDIRECT_URI` | api, worker | Conditional | No |  | Trello OAuth callback URL registered with the provider. |
| `TRELLO_SCOPES` | api, worker | Conditional | No |  | Space-separated Trello OAuth scopes. |
| `ATLASSIAN_MCP_TRUSTED_BINDINGS` | api, worker, storage-worker | No | No |  | JSON list of trusted Atlassian MCP operations and contract digests. |

### Slack

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `SLACK_CONFIGURATION` | api, worker | Conditional | Yes |  | Slack app JSON, including the client and signing secrets. |
| `SLACK_INTAKE_ENABLED` | api | No | No | `false` | `true` accepts Slack events. |
| `SLACK_OUTBOUND_ENABLED` | api, worker | No | No | `false` | `true` lets agents post to Slack. |
| `SLACK_CHANNEL_AGENTS_ENABLED` | api, worker | No | No | `false` | `true` enables agents in Slack channels. Requires member linking. |
| `SLACK_PUBLIC_DELIVERY_ENABLED` | api, worker | No | No | `false` | `true` allows public channel replies. Requires channel agents. |
| `SLACK_LINK_PROMPTS_ENABLED` | api, worker | No | No | `false` | `true` prompts Slack members to link accounts. |
| `SLACK_DIRECT_MESSAGES_ENABLED` | worker | No | No | `false` | `true` enables direct messages. Requires link prompts. |

### Workspace MCP

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `WORKSPACE_MCP_ADMISSION_ENABLED` | api, worker | No | No |  | `true` admits workspace MCP servers. |
| `WORKSPACE_MCP_DISPATCH_ENABLED` | api, worker | No | No |  | `true` dispatches tool calls to workspace MCP servers. |

### Skills and code steps

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `SKILL_SCRIPTS_ENABLED` | api, worker, snippet-broker | No | No | `false` | `true` runs skill scripts through the snippet broker. |
| `WORKFLOW_CODE_STEPS_ENABLED` | api, worker, storage-worker | No | No | `false` | `true` enables workflow code steps. |
| `SNIPPET_BROKER_URL` | api, worker | Conditional | No |  | Snippet broker URL. |
| `SNIPPET_BROKER_TOKEN` | api, worker | Conditional | Yes |  | Bearer token shared with the snippet broker. |
| `SKILL_BROKER_STATUS_URL` | api, worker | Conditional | No |  | Snippet broker status URL. |
| `SNIPPET_ALLOW_LOCAL_HTTP` | api, worker | No | No | `false` | `true` allows a plain-HTTP broker URL for local development. |
| `SNIPPET_BROKER_TOKEN_FILE` | snippet-broker | Yes | No |  | Path to the file holding the broker token. |
| `SNIPPET_IMAGE` | snippet-broker | Yes | No |  | Container image that runs snippets. |
| `SNIPPET_DATABASE` | snippet-broker | No | No | `/data/jobs.sqlite` | SQLite job database path. |
| `SNIPPET_RUNTIME` | snippet-broker | No | No | `runsc` | Container runtime: `runsc` or `runc`. |
| `SNIPPET_ALLOW_LOCAL_RUNC` | snippet-broker | No | No | `false` | `true` allows the `runc` runtime for local development. |

### Recommendations

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `RECOMMENDATION_MODEL_FAMILY` | api, worker | Conditional | No |  | Model family for recommendations. Unset disables them. |
| `RECOMMENDATION_PERIOD_SECONDS` | api, worker | No | No |  | Sweep period. |
| `RECOMMENDATION_CONCURRENCY` | api, worker | No | No |  | Concurrent recommendation runs. |
| `RECOMMENDATION_TIMEOUT_MS` | api, worker | No | No |  | Per-run timeout. |
| `RECOMMENDATION_MAX_INPUT_BYTES` | api, worker | No | No |  | Maximum input size per run. |
| `RECOMMENDATION_MAX_OUTPUT_TOKENS` | api, worker | No | No |  | Maximum output tokens per run. |
| `RECOMMENDATION_MAX_RUN_PICO_USD` | api, worker | No | No |  | Maximum cost per run, in pico-USD. |
| `RECOMMENDATION_WORKSPACE_PICO_USD` | api, worker | No | No |  | Workspace budget per period, in pico-USD. |
| `RECOMMENDATION_PLATFORM_PICO_USD` | api, worker | No | No |  | Platform budget per period, in pico-USD. |

### Telemetry and flags

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `CLOUD_TELEMETRY_ENABLED` | api, worker, storage-worker, snippet-broker, database | No | No | `false` | `true` exports OpenTelemetry data in production. |
| `CLOUD_TELEMETRY_OTLP_ENDPOINT` | api, worker, storage-worker, snippet-broker, database | Conditional | No |  | OTLP HTTP endpoint. |
| `CLOUD_TELEMETRY_OTLP_AUTHORIZATION` | api, worker, storage-worker, snippet-broker, database | Conditional | Yes |  | OTLP `Authorization` header value. |
| `CLOUD_TELEMETRY_SAMPLE_RATIO` | api, worker, storage-worker, snippet-broker, database | No | No | `0.1` | Trace sample ratio between 0 and 1. |
| `FEATURE_FLAGS_OFF` | api, worker, storage-worker, snippet-broker, database | No | No |  | Comma-separated flags to turn off when the flag provider gives no answer. A flag's own variable wins. |
| `FEATURE_FLAG_SOUL_REPOSITORY_EXPLORER` | api, worker | No | No | `on outside production` | `true` or `false` sets the `soul-repository-explorer` flag when the flag provider gives no answer: an admin-only, permission-filtered, read-only explorer in workspace settings. |
| `FEATURE_FLAG_PUBLIC_TULIPFARM_GUIDE` | api, worker | No | No | `on outside production` | `true` or `false` sets the `public-tulipfarm-guide` flag when the flag provider gives no answer: Public website guide, bounded model answers and inline signup. |
| `FEATURE_FLAG_GOOGLE_CALENDAR_CANVAS` | api, worker | No | No | `on outside production` | `true` or `false` sets the `google-calendar-canvas` flag when the flag provider gives no answer: Calendar read and action canvas cards and approved Google Meet creation. |
| `FEATURE_FLAG_SLACK_APP_SENDER` | api, worker | No | No | `on outside production` | `true` or `false` sets the `slack-app-sender` flag when the flag provider gives no answer: Workflow and agent Slack sends can post as the TulipFarm app instead of the requester. |
| `FEATURE_FLAG_DEFAULT_CONNECTION_KNOWLEDGE` | api, worker | No | No | `on outside production` | `true` or `false` sets the `default-connection-knowledge` flag when the flag provider gives no answer: New eligible integration enablements automatically get owner-only Knowledge with ongoing discovery. |

### Self-host setup

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `TULIPFARM_DATABASE_ADMIN_URL` | database | Yes | Yes |  | PostgreSQL administrator URL used once to create logins and databases. |
| `TULIPFARM_DATABASE_HOST` | database | No | No |  | Database host that services use, if it differs from the admin URL host. |
| `TULIPFARM_OBJECT_STORAGE_ENDPOINT` | database | Yes | No |  | S3-compatible endpoint. |
| `TULIPFARM_OBJECT_STORAGE_ACCESS_KEY_ID` | database | Yes | No |  | Object-storage access key that setup uses and hands to services. |
| `TULIPFARM_OBJECT_STORAGE_SECRET_ACCESS_KEY` | database | Yes | Yes |  | Object-storage secret key. |
| `TULIPFARM_OBJECT_STORAGE_BUCKET` | database | No | No | `tulipfarm-soul` | Bucket for agent soul files. |
| `TULIPFARM_OBJECT_STORAGE_REGION` | database | No | No | `auto` | Object-storage region. |

### Operator tools

| Name | Services | Required | Secret | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `DATABASE_ADMIN_URL` | database | Conditional | Yes |  | Administrator URL for local database tools and migrations. |
| `DATABASE_MIGRATION_URL` | database | Conditional | Yes |  | Migration-owner URL for the database CLI. |
| `TULIPFARM_DATABASE_SECRET_STORE` | database | No | No |  | Path to a module whose default export `{ read, write }` stores production database secrets. Unset reads environment variables only. |
