Repository navigation
Expand file tree
/
Copy path.env.example
More file actions
357 lines (327 loc) · 20.3 KB
/
Copy path.env.example
File metadata and controls
357 lines (327 loc) · 20.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# Switch local development configuration
#
# Do NOT copy this file to .env by hand: the secret fields below ship BLANK on
# purpose so no known default credential ever reaches a running stack. Generate
# a .env with strong random secrets instead:
#
# just init-env
#
# That fills every blank secret (admin passwords, DB password, JWT key, Matrix
# registration secret, agent token) with a freshly generated value and prints
# the resulting gateway admin login.
# ── Standalone images (GHCR) ─────────────────────────────────────────────────
# Coordinates for the published switch-core / gateway / setup images that the
# standalone stack pulls. Set SWITCH_VERSION to a released tag (e.g. 0.3.0) for
# a reproducible stack. It is REQUIRED and has no default in the compose file:
# it used to fall back to `latest`, so a missing or misspelt value silently
# floated the whole stack to whatever had most recently been published, with
# nothing to say so. Compose now refuses to start instead.
# Repo users building from source (`just standalone-up`) can ignore these.
SWITCH_REGISTRY=ghcr.io
SWITCH_IMAGE_NAMESPACE=sandbox-quantum
SWITCH_VERSION=latest
# Host ports each service publishes. Defaults match the values baked in before
# these knobs existed; override any that clash with something already running on
# your machine (Switch Console's local-server mode picks free ports automatically).
GATEWAY_HOST_PORT=3000
API_HOST_PORT=8000
MATTERMOST_HOST_PORT=8065
POSTGRES_HOST_PORT=5432
# Host interface the published ports bind to. Defaults to loopback so the stack
# is reachable only from this machine; set to 0.0.0.0 to expose it on the
# network — do that only behind a reverse proxy / firewall.
SWITCH_BIND_ADDR=127.0.0.1
# ── Switch database (docker compose) ──────────────────────────────────────────
# Two roles, not one, because row-level security is inert against the role
# that owns the tables it protects — Postgres exempts a table's owner from its
# own policies. So DB_USER below is deliberately NOT the owner:
#
# DB_USER / DB_PASSWORD the RUNTIME role. Every request switch-core serves
# authenticates as this role, so it is the one the
# tenant-isolation policies actually apply to. It is
# a plain LOGIN role that owns nothing and can
# create nothing — `just up`'s init-db container
# creates it, and switch-core grants it CRUD on the
# schema at boot, once the owner connection has run
# migrations.
# DB_OWNER_USER / DB_OWNER_PASSWORD
# the SCHEMA OWNER, used for exactly two things:
# running Alembic at boot, and re-issuing the
# runtime role's grants right after. It is never
# used to serve a request. The container's Postgres
# superuser is this role now, not DB_USER — see
# deploy/local/docker-compose.yml.
#
# If DB_USER were the owner, switch-core would refuse to start:
# DB_REQUIRE_RESTRICTED_ROLE (default true) checks the runtime connection is
# not a superuser, does not bypass RLS, and owns no policied table, precisely
# because a deployment that believes it is isolating tenants and is not looks
# identical to one that is, until a second tenant reads the first's rooms.
DB_HOST=localhost
DB_PORT=5432
DB_USER=switch_app
DB_PASSWORD=
DB_OWNER_USER=postgres
DB_OWNER_PASSWORD=
DB_NAME=switch
# TLS for the Postgres connection: disable | allow | prefer | require |
# verify-ca | verify-full. Local dev and an in-cluster database stay plain;
# a managed database (RDS / Cloud SQL / Azure) needs at least "require".
# DB_SSL_MODE=disable
# PEM bundle of certificate authorities the server certificate is checked
# against. Only for the two verifying modes, and needed there because a managed
# database is signed by the provider's own root rather than a public one.
# DB_SSL_ROOT_CERT=/etc/ssl/certs/rds-global-bundle.pem
# ── Logging ──────────────────────────────────────────────────────────────────
# "text" for a terminal, "json" for a log pipeline that parses fields.
# LOG_FORMAT=text
# LOG_LEVEL=INFO
# SWITCH_LOG_LEVEL=INFO
# Emitted on every JSON line as `service` / `env`.
# SERVICE_NAME=switch-core
# ENVIRONMENT=development
# What a log line says when no tenant is bound to it. A request logs the
# caller's tenant and background work logs the tenant of the row it is acting
# on, so this only covers lines belonging to neither — which are also the lines
# that can write nothing. Not a tenant id, and setting it to one would make
# every unattributed line look like that tenant's own.
# TENANT_ID=default
# ── Observability ────────────────────────────────────────────────────────────
# Where this deployment reports metrics and logs. Unset — the default — means
# it reports nowhere, and nothing measured leaves the process. Readiness
# checking runs either way: /health/ready answers whether or not this is set.
#
# A base URL with no path. `/v1/metrics` and `/v1/logs` are appended, the same
# convention OTEL_EXPORTER_OTLP_ENDPOINT follows, so pasting a full signal URL
# here is refused at startup rather than posting to /v1/logs/v1/metrics.
# OTLP_ENDPOINT=https://telemetry.example.com
#
# A UUID naming this deployment, stable across restarts. Required whenever the
# endpoint is set: the collector drops payloads it cannot attribute, silently
# and with a 200, so without one the server would report nothing while looking
# correctly configured — which is why it refuses to start instead. Generate it
# once with `uuidgen`; a fresh one per restart makes a single deployment look
# like an endless population of new installs.
# DEPLOYMENT_ID=
#
# Per signal. Metrics are the point and are on as soon as an endpoint is named.
# Logs are off because they already reach this container's output, where a
# cluster's log agent can read them — turning this on sends a second copy over
# the network. There is no traces setting: nothing produces spans yet, and a
# flag that changes nothing is worse than an absent one.
# OTLP_METRICS_ENABLED=true
# OTLP_LOGS_ENABLED=false
#
# `key=value` pairs, comma-separated, on every request. Needed for a collector
# that authenticates; the relay does not.
# OTLP_HEADERS=
# OTLP_TIMEOUT_SECONDS=10
# OTLP_EXPORT_INTERVAL_SECONDS=60
# ── Product telemetry ────────────────────────────────────────────────────────
# Anonymous usage counts, off unless switched on (docs/old/telemetry-events.md).
# TELEMETRY_ENABLED=false
#
# Which Amplitude project this server's usage lands in: prod, staging, dev or
# local. Unset means prod, which is right for every customer deployment. This
# file is for a developer's machine, so it says local, keeping a local run's
# usage out of the production numbers if telemetry is ever switched on.
TELEMETRY_ENVIRONMENT=local
# ── Avatars ──────────────────────────────────────────────────────────────────
# An agent with no icon of its own is drawn by api.dicebear.com with its name as
# the seed, and a person relayed from another platform by ui-avatars.com with
# their name in the URL. Chat clients load those images, so the services see
# the name and each reader's address. Set false to send no such URL: each
# platform shows its own default icon instead.
# THIRD_PARTY_AVATARS_ENABLED=true
# ── Client identity ──────────────────────────────────────────────────────────
# The server half of every member's `@localpart:server` id. Nothing is
# contacted at it; the ids are stable public handles. (MATRIX_SERVER_NAME, the
# old name, is still accepted for one release.)
ID_SERVER_NAME=localhost
# ── Agent registration ───────────────────────────────────────────────────────
AGENT_REGISTRATION_TOKEN=
# ── Agent management (experimental) ──────────────────────────────────────────
# Machines running an agents controller, and the agents placed on them (the
# gateway's Machines page). Off unless FEATURE_FLAGS_ENABLED below lists
# `agent_management`. When on, CONTROLLER_TOKEN_SECRET is required: at least
# 32 random characters, separate from SECRET_KEYS, e.g. `openssl rand -base64 48`.
CONTROLLER_TOKEN_SECRET=
# The agents controller release Core tells standalone and cloud controllers to
# run: they install it when idle, checking this SHA-256. All three or none;
# none leaves every controller on the version it has.
# CONTROLLER_RELEASE_VERSION=
# CONTROLLER_RELEASE_URL=
# CONTROLLER_RELEASE_SHA256=
# ── Feature flags ────────────────────────────────────────────────────────────
# Flags turned on for this deployment, comma-separated (e.g.
# `ecosystem.show_owners`). Every other flag is off. They are fixed at deploy
# time: no one can change them while the server runs. An unknown flag stops
# startup. Known flags:
# ecosystem.show_owners owners on the ecosystem graph
# agent_management managed agents and the machines that run them
# switch_cloud Switch Cloud
# hosted_agents offers cloud machines in Switch Console; this
# server runs them only with HOSTED_LAUNCH_CAPACITY
# above 0 (which needs agent_management)
# service_connections people connect outside services (GitHub
# grants, Atlassian, Google Workspace, Datadog)
# and grant them to their agents
# agent_chats an agent's chats and rooms on its page in
# Switch Console
# switch_buddy each person's own assistant, created by Switch
# Console at the end of its first run (needs
# agent_management)
FEATURE_FLAGS_ENABLED=
# ── Server keys ──────────────────────────────────────────────────────────────
# Master keys every signing and encryption key is derived from:
# "<id>:<secret>" comma-separated, current first, secrets of 32+ characters.
# `just init-env` generates one. To rotate, put a new entry first and keep the
# old one until a boot has re-encrypted stored values; see
# docs/old/key-rotation.md.
SECRET_KEYS=
# Legacy: the single secret used before SECRET_KEYS. An existing .env keeps its
# value through the upgrade so sessions and stored credentials keep working;
# remove it once a boot has re-encrypted them. A new .env leaves it empty.
JWT_SECRET_KEY=
# ── Gateway auth ─────────────────────────────────────────────────────────────
GATEWAY_ADMIN_EMAIL=admin@switch.local
GATEWAY_ADMIN_PASSWORD=
# Off by default: a person who belongs to more than one tenant and has not
# selected one on their session gets a 403, same as a single-tenant deployment
# does today, rather than a 409 listing the tenants to choose from. That 409 is
# a breaking change for any client that has never had to handle it — turn this
# on only once the client authenticating against this deployment does. See
# docs/old/multi-tenancy-phase2-tenants.md, §4.
# GATEWAY_TENANT_CHOICE_ENABLED=false
# Where a first-time IdP sign-in lands: `default_tenant` (the one pre-existing
# workspace), `invite_only` (no workspace until an invitation is accepted), or
# `open` (no workspace, and they may create their own, capped per person).
# GATEWAY_SIGNUP_MODE=default_tenant
# How many workspaces one person may own here. Creating a workspace is an
# amplification vector rather than a row — every tenant adds a fan-out at boot
# and to a sweep that runs every few seconds — so the route is bounded. Set it
# to 0 to refuse workspace creation outright; this one value is both the cap
# and the gate. Counts owner memberships only, and deployment operators are
# exempt. See docs/old/multi-tenancy-phase2-tenants.md, §5.
# GATEWAY_MAX_WORKSPACES_PER_USER=3
# Invitation e-mails. Set a host to send an invitation addressed to an e-mail
# through this SMTP relay; unset, the invitation is still created and the admin
# shares the link. Needs FRONTEND_BASE_URL (the link points there). TLS is
# `starttls` (587), `tls` (465) or `none` (a local relay only). Username and
# password go together or not at all.
# GATEWAY_SMTP_HOST=smtp.example.com
# GATEWAY_SMTP_PORT=587
# GATEWAY_SMTP_TLS=starttls
# GATEWAY_SMTP_USERNAME=
# GATEWAY_SMTP_PASSWORD=
# GATEWAY_SMTP_FROM=Switch <invites@example.com>
# GATEWAY_INVITE_EMAILS_PER_DAY=50
# ── Frontend ─────────────────────────────────────────────────────────────────
FRONTEND_BASE_URL=http://localhost:5173
# Public origin of the gateway HTTP API (used to build the switchdash:// deeplink
# HTTP redirect so "Open in Switch Console" is clickable on Discord, Telegram
# and other http-only platforms). Leave unset to post the raw switchdash://
# deeplink. Also the --server the gateway's "Add machine" dialog shows for
# enrolling an agents controller; without it the dialog shows no command.
# GATEWAY_PUBLIC_URL=http://localhost:8000
# Public origin a messaging platform reaches Switch on: the base of the OAuth
# redirect and the event URLs under /messaging for the distributed Slack,
# Discord and Teams apps.
# Must be https and must resolve from the internet, so it is usually a
# different host from GATEWAY_PUBLIC_URL. Required to offer workspace installs.
# MESSAGING_PUBLIC_URL=https://switch.example.com
# Credentials of the distributed Slack app — the one a customer installs by
# clicking a button, not the one an operator registers for themselves (that is
# SLACK_BOT_TOKEN et al). Set all three or none; setting some is refused at
# startup. See docs/old/bridges/SLACK_DISTRIBUTED_APP.md.
# SLACK_APP_CLIENT_ID=
# SLACK_APP_CLIENT_SECRET=
# SLACK_APP_SIGNING_SECRET=
# Credentials of the distributed Discord app — the one a customer adds to their
# server by clicking "Add to Server", not the self-registered app whose token an
# operator pastes in (DISCORD_SETUP.md). Set all four or none; setting some is
# refused at startup, and MESSAGING_PUBLIC_URL must be set with them. The bot
# token lives here, in deployment config, because a Discord install carries no
# per-install token. See docs/old/bridges/DISCORD_DISTRIBUTED_APP.md.
# DISCORD_APP_CLIENT_ID=
# DISCORD_APP_CLIENT_SECRET=
# DISCORD_APP_BOT_TOKEN=
# DISCORD_APP_APPLICATION_ID=
# Privileged intents on the shared connection, each off by default (mention-only
# / API member fetches) and requiring Discord verification past ~100 guilds.
# DISCORD_APP_MESSAGE_CONTENT=false
# DISCORD_APP_MEMBERS=false
# The distributed Teams app — one multi-tenant Entra app backing a SingleTenant
# Azure Bot in your own directory, which a customer's Microsoft admin approves
# for their organisation from Switch; not the bring-your-own app an operator
# registers per bridge (TEAMS_SETUP.md). The client id, tenant id, notification
# keypair and privacy/terms URLs are all required together, with exactly one
# credential (a secret, a certificate and its key, or a federated token file)
# and MESSAGING_PUBLIC_URL. One app per environment, never shared. See
# docs/old/bridges/TEAMS_DISTRIBUTED_APP.md.
# TEAMS_APP_CLIENT_ID=
# TEAMS_APP_TENANT_ID=
# TEAMS_APP_CLIENT_SECRET=
# TEAMS_APP_CERTIFICATE=
# TEAMS_APP_CERTIFICATE_PRIVATE_KEY=
# TEAMS_APP_FEDERATED_TOKEN_FILE=
# TEAMS_APP_NOTIFICATION_CERTIFICATE=
# TEAMS_APP_NOTIFICATION_PRIVATE_KEY=
# TEAMS_APP_NOTIFICATION_PREVIOUS_PRIVATE_KEY=
# TEAMS_APP_PRIVACY_URL=
# TEAMS_APP_TERMS_URL=
# Optional: the app's name in Teams (30 characters at most; default "Agent
# Switch"). Give each non-production environment's app its own, e.g.
# "Agent Switch (dev)", so an organisation approving more than one can tell
# them apart.
# TEAMS_APP_NAME=
# The distributed Telegram app — one bot per deployment whose groups a customer
# claims with a link, not the self-registered bot whose token an operator pastes
# in (TELEGRAM_SETUP.md). Set both or neither, with MESSAGING_PUBLIC_URL on port
# 443, 80, 88 or 8443. The webhook secret is 32-256 characters of A-Z a-z 0-9 _ -
# and is what proves an update came from Telegram (openssl rand -hex 32). Turn Group Privacy off in
# BotFather before the bot joins any chat. See
# docs/old/bridges/TELEGRAM_DISTRIBUTED_APP.md.
# TELEGRAM_APP_BOT_TOKEN=
# TELEGRAM_APP_WEBHOOK_SECRET=
# ── Mattermost (local dev) ───────────────────────────────────────────────────
MATTERMOST_ADMIN_USER=admin
MATTERMOST_ADMIN_PASSWORD=
MATTERMOST_TEAM_NAME=switch
MATTERMOST_USER=user
MATTERMOST_USER_PASSWORD=
# Teams and Telegram have no local-dev env vars: both are connected per-bridge
# through the gateway (all credentials live in the bridge's stored
# connection_config), never in global config.
# ── Outbound URLs ────────────────────────────────────────────────────────────
# Private hosts Switch may reach at a URL a tenant or agent supplied (a
# Mattermost server, an OpenCode server, an agent icon): hostnames and CIDRs,
# comma-separated. Every other non-public address is refused. `localhost`
# covers the local-dev Mattermost and an OpenCode server on this machine; the
# standalone compose always adds `mattermost` to whatever is listed here.
OUTBOUND_ALLOWED_PRIVATE_HOSTS=localhost
# ── OIDC (optional — MCP OAuth token validation; bring your own IdP) ─────────
# Enable OAuth/OIDC token auth on the MCP server by pointing at any standards
# compliant IdP. Leave unset to use API-token (bearer) auth only, which is the
# default for the local stack. OAUTH_AUDIENCE is required with the issuer.
# OAUTH_ISSUER_URL=https://your-idp.example.com/realms/switch
# OAUTH_AUDIENCE=switch
# OAUTH_VERIFY_ISSUER=true
# ── Gateway OIDC login (optional — bring your own IdP for the browser login;
# distinct from the OAUTH_* block above) ──────────────────────────────────────
# See docs/old/GATEWAY_OIDC_SETUP.md before setting these, especially if the
# provider is WorkOS: it needs a Connect application, not a User Management
# client id. Issuer/client id/secret/scopes are all-or-nothing — set all four
# or none. Quote GATEWAY_OIDC_SCOPES, and include "openid": the server refuses
# to start without it, because no id_token is issued for a scope list missing
# it.
# GATEWAY_OIDC_ISSUER_URL=https://<your-idp-or-authkit-domain>
# GATEWAY_OIDC_CLIENT_ID=<client-id>
# GATEWAY_OIDC_CLIENT_SECRET=<client-secret>
# GATEWAY_OIDC_SCOPES="openid profile email"
# GATEWAY_OIDC_PROVIDER_LABEL=SSO
# One sign-in button per entry instead of one labelled as above, each sending
# its params with the authorization request (WorkOS: provider=GoogleOAuth …):
# GATEWAY_OIDC_LOGIN_OPTIONS='[{"id":"google","label":"Google","params":{"provider":"GoogleOAuth"}},{"id":"github","label":"GitHub","params":{"provider":"GitHubOAuth"}}]'
# GATEWAY_OIDC_REDIRECT_URL=http://localhost:8000/gateway/auth/oidc/callback
# GATEWAY_OIDC_REQUIRE_EMAIL_VERIFIED=true