Use .env.example as the source of truth for defaults and available settings.
This document groups the settings by operational area and calls out the values
that most often matter in local development and deployment.
ENVIRONMENT: defaults tolocal. Non-local deployments should provide explicit runtime secrets such asPOSTGRES_URLandMINIO_ROOT_PASSWORD. Missing runtime dependencies are reported through health/runtime failures where possible instead of eager settings-construction errors.LOG_LEVEL: defaults toINFO.API_SHARED_SECRET: required for protected non-dashboard API routes and for./scripts/dev.sh login.CONFIG_SECRET_KEY: environment or.envkey used to encrypt secret values saved from the admin dashboard configuration page. This key is not dashboard-managed, and dashboard-managed secret saves are rejected when it is unset.WEBHOOK_SHARED_SECRET: optional separate secret for external/webhooks/*callers such as DocuSeal, Google Forms, and EspoCRM. When unset, webhook routes fall back toAPI_SHARED_SECRETfor compatibility.
The admin dashboard can store a small allowlist of movable integration
credentials and business knobs in Postgres. Non-empty env or .env values
always win and appear as environment-locked in the dashboard. If no env value is
present, the database value overrides the code default.
Secret values saved from the dashboard are encrypted before storage using
CONFIG_SECRET_KEY. API responses never include full secret values. Database
secrets return configured state and a short first/last-character mask for
confirmation; env and .env secrets return only configured state.
Core bootstrap systems such as EspoCRM, Authentik, and Migadu remain env-managed and are intentionally not dashboard-configurable. Onboarding email SMTP settings are dashboard-configurable under the Onboarding category when env overrides are not set.
Onboarding Tally intake settings are dashboard-configurable under Intake. If
ONBOARDING_TALLY_API_KEY or ONBOARDING_TALLY_WEBHOOK_SIGNING_SECRET is set
in .env or the process environment, that env value wins and the dashboard
shows the field as environment-locked. Legacy TALLY_* env aliases still work
for compatibility.
Newsletter sync settings are normally set from the admin dashboard
configuration page. A non-empty env or .env value locks the matching
dashboard field.
ONBOARDING_TALLY_API_KEY: optional Tally API key for future onboarding-form backfills. The webhook intake path does not require it.ONBOARDING_TALLY_WEBHOOK_SIGNING_SECRET: secret used to verifyTally-Signatureon/webhooks/tally/onboarding. When unset, the route falls back toWEBHOOK_SHARED_SECRET/API_SHARED_SECRETusing the existingX-API-Secretheader path.ONBOARDING_TALLY_ALLOWED_FORM_IDS: comma-separated allowlist of accepted onboarding Tally form IDs. Tally intake fails closed when this is unset.POST /webhooks/tally/onboarding?dry_run=true: validates auth/signature, checks the form allowlist, and returns the normalized intake payload plus the job metadata it would enqueue without queueing work, writing to the CRM, writing to the DB, or fetching uploaded resumes.POST /webhooks/tally/onboarding?dry_run=worker: validates and maps the webhook, then enqueues an intake worker job withdry_run=true. The worker performs CRM lookup and builds planned CRM updates, but skips CRM writes and intake DB persistence.INTAKE_RESUME_REQUIRE_VIRUS_SCAN: when true, downloaded resume files are not parsed unless the malware scan command succeeds. Defaults to false locally; non-local runtimes require scanning for resume parsing even when this is unset.INTAKE_RESUME_VIRUS_SCAN_COMMAND: command used to scan downloaded resumes. Required whenINTAKE_RESUME_REQUIRE_VIRUS_SCAN=trueor when running outside local/dev/test. Include{path}where the temporary resume filepath should be inserted. When{path}is omitted, the filepath is appended as the final argument. Production Compose uses the ClamAV sidecar commandclamdscan --stream --no-summary --config-file=/etc/clamav/clamdscan.conf {path}.INTAKE_RESUME_VIRUS_SCAN_TIMEOUT_SECONDS: scan command timeout.
REDIS_URLREDIS_QUEUE_NAMEREDIS_KEY_PREFIXJOB_TIMEOUT_SECONDSJOB_RESULT_TTL_SECONDSJOB_MAX_ATTEMPTSJOB_RETRY_BASE_SECONDSJOB_RETRY_MAX_SECONDSGIG_RECRUITING_STALE_DAYSGIG_CONTACTED_REMINDER_DAYSGIG_RECRUITING_REMINDER_MAX_AGE_DAYS
./scripts/dev.sh overrides local Redis settings to deterministic per-worktree
localhost ports. Compose injects Docker-network URLs.
POSTGRES_URLPOSTGRES_DBPOSTGRES_USERPOSTGRES_PASSWORDPOSTGRES_HOST_BINDPOSTGRES_HOST_PORT
For local dev, ./scripts/dev.sh and ./scripts/docker-compose.sh compute
deterministic per-worktree ports unless values are pinned in .env or the
invoking shell.
Inside Conductor, CONDUCTOR_PORT is treated as the first port in the
workspace's 10-port range for unset worktree defaults: Redis uses +0,
Postgres +1, Compose web +2, MinIO API +3, MinIO console +4,
host-run web/API +5, and bot health +6. Explicit service port overrides keep
their current precedence rules.
MINIO_ENDPOINTMINIO_INTERNAL_BUCKETMINIO_ROOT_USERMINIO_ROOT_PASSWORDMINIO_HOST_BINDMINIO_API_HOST_PORTMINIO_CONSOLE_HOST_PORT
Use MINIO_ROOT_USER and MINIO_ROOT_PASSWORD as the actual env vars.
MINIO_ACCESS_KEY and MINIO_SECRET_KEY are settings aliases, not env-loaded
fields.
WEB_HOSTWEB_PORTWEB_HOST_BINDWEB_HOST_PORTDASHBOARD_DEFAULT_PATHDASHBOARD_PUBLIC_BASE_URL(public browser origin for generated dashboard links and dashboard write CSRF checks)
Deprecated fallback names still work for now:
WEBHOOK_INGEST_HOSTWEBHOOK_INGEST_PORTWEBHOOK_INGEST_HOST_BINDWEBHOOK_INGEST_HOST_PORT
Host-run ./scripts/dev.sh ignores .env for WEB_PORT and computes a
deterministic per-worktree value unless WEB_PORT is exported in the shell.
OIDC settings:
OIDC_ISSUER_URLOIDC_CLIENT_IDOIDC_CLIENT_SECRETOIDC_SCOPEOIDC_GROUPS_CLAIMOIDC_ADMIN_GROUPSOIDC_CALLBACK_PATHOIDC_REDIRECT_BASE_URLAUTH_SESSION_COOKIE_NAMEAUTH_SESSION_TTL_SECONDS
Discord dashboard-link settings:
DISCORD_SERVER_IDDISCORD_ADMIN_ROLESDISCORD_API_TIMEOUT_SECONDSDISCORD_LINK_TTL_SECONDSDISCORD_LINK_REQUIRE_OIDC_IDENTITY_CHECKSDISCORD_BOT_TOKEN
Local .env.example sets DISCORD_LINK_REQUIRE_OIDC_IDENTITY_CHECKS=false so
Discord dashboard links and CLI-created dev links can create sessions without an
OIDC roundtrip. Production should keep identity checks enabled.
WORKER_NAMEWORKER_QUEUE_NAMESWORKER_BURSTWORKER_API_BASE_URLDISCORD_BOT_INTERNAL_BASE_URL
Worker startup currently resolves to one effective queue name. Keep this explicit if true multi-queue routing is introduced later.
ESPO_BASE_URLESPO_API_KEYCRM_SYNC_ENABLED: optional, defaults totrue; the scheduler starts only when ESPO credentials are configured.CRM_SYNC_INTERVAL_SECONDSCRM_SYNC_PAGE_SIZECHECK_EMAIL_WAITMAX_ATTACHMENTS_PER_CONTACTMAX_FILE_SIZE_MBALLOWED_FILE_TYPESRESUME_EXTRACTOR_VERSIONINTAKE_RESUME_FETCH_TIMEOUT_SECONDSINTAKE_RESUME_MAX_REDIRECTSINTAKE_RESUME_ALLOWED_HOSTS
Worker CRM wiring uses the fixed LinkedIn field cLinkedIn, keeps the
intake-completed field unset, and matches resume filenames with
resume, cv, and curriculum.
OPENAI_API_KEYOPENAI_BASE_URLOPENAI_MODELOPENAI_DIRECT_API_KEY/OPENAI_API_KEY_DIRECTOPENAI_DIRECT_BASE_URLOPENAI_DIRECT_MODELFIREWORKS_API_KEYOPENROUTER_API_KEYLANGFUSE_BASE_URLRESUME_AI_API_KEYRESUME_AI_BASE_URLRESUME_AI_MODELJOB_LEAD_CLASSIFIER_ENABLEDJOB_LEAD_CLASSIFIER_MODELJOB_LEAD_CLASSIFIER_TIMEOUT_SECONDS
Resume/profile LLM calls retry matching direct providers after Bifrost request failures when direct provider credentials are configured.
Discord bot:
DISCORD_BOT_TOKENBACKEND_API_BASE_URLHEALTHCHECK_PORTDISCORD_DEFAULT_JOB_FORUM_CHANNELSDISCORD_LOGS_WEBHOOK_URLDISCORD_LOGS_WEBHOOK_WAIT
Agent gateway:
AGENT_API_TIMEOUT_SECONDSAGENT_FAST_MODEL,AGENT_FAST_BASE_URL,AGENT_FAST_API_KEYAGENT_STRONG_MODEL,AGENT_STRONG_BASE_URL,AGENT_STRONG_API_KEYAGENT_REASONING_MODEL,AGENT_REASONING_BASE_URL,AGENT_REASONING_API_KEYAGENT_FALLBACK_MODELAGENT_STRUCTURED_PLANNER_ENABLEDAGENT_STRUCTURED_PLANNER_TIMEOUT_SECONDSAGENT_INTENT_NORMALIZER_ENABLEDAGENT_INTENT_NORMALIZER_TIMEOUT_SECONDSGITHUB_API_TOKENGITHUB_DEFAULT_REPOGITHUB_ALLOWED_REPOS
Agent model base URLs must be HTTPS endpoints on allowed provider hosts, except
the internal Docker-network Bifrost URL http://bifrost:8080/openai is allowed
for same-host deployments.
MIGADU_API_USER,MIGADU_API_KEY: required for/create-mailboxand/create-user-accounts.MIGADU_MAILBOX_DOMAIN: optional, defaults to508.dev.BREVO_API_KEY: optional for Brevo newsletter sync.BREVO_API_BASE_URL: optional, defaults tohttps://api.brevo.com/v3.BREVO_API_TIMEOUT_SECONDS: optional, defaults to20.0.BREVO_508_MEMBERS_NEWSLETTER_LIST_ID: optional explicit Brevo list ID override; use4for the 508 members list when setting it directly.BREVO_508_MEMBERS_NEWSLETTER_LIST_NAME: optional, defaults to508 membersand is used to look up the list ID when the explicit ID is unset.KEILA_API_KEY: optional for Keila contact sync.KEILA_API_BASE_URL: optional, defaults tohttps://app.keila.io.KEILA_API_TIMEOUT_SECONDS: optional, defaults to20.0.NEWSLETTER_SYNC_ENABLED: optional, defaults tofalse; dashboard changes require an API restart because the scheduler starts at startup.NEWSLETTER_SYNC_INTERVAL_SECONDS: optional, defaults to604800; dashboard changes require an API restart because the scheduler sleep interval is startup-bound.NEWSLETTER_SYNC_EXCLUDED_MAILBOXES: optional comma-separated mailbox local-parts or full addresses to skip during Migadu resync.
Mailbox and backup email subscription to configured newsletter tools is best
effort. Failures are reported as warnings and do not block mailbox or account
creation. The periodic sync uses Migadu mailboxes and password recovery emails
as the source of truth for @508.dev. When CRM is configured, it only syncs
mailboxes that match a CRM contact; it also skips configured excluded mailboxes
and does not re-add provider-suppressed contacts.