-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.env.example
More file actions
333 lines (301 loc) · 16.2 KB
/
Copy path.env.example
File metadata and controls
333 lines (301 loc) · 16.2 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
# Copy this file to .env before starting the stack:
#
# cp .env.example .env
#
# Every variable up to HUB_STATIC_DIR is required; everything below
# it is optional (see its own comment). Boot validates the whole file
# and reports every missing or malformed value at once — nothing is
# silently defaulted.
# Postgres connection URL for your local Postgres (see the README's
# "Running locally" section for a one-time setup). Prefer an explicit
# username (postgres://<user>@localhost:5432/workbench) — environments
# without $USER cannot infer one.
DATABASE_URL=postgres://localhost:5432/workbench
# The single public origin the stack serves from. `workbench setup` and
# `workbench seed` also read this to find the hub, unless HUB_URL is
# set separately.
BASE_URL=http://localhost:3000
# Secret used to sign browser sessions; any string of at least 32
# characters. The value below is fine for a laptop that only you can
# reach; generate your own for anything else: openssl rand -hex 32
SESSION_SECRET=insecure-dev-only-session-secret-0000
# Directory where the hub keeps durable repo and asset state. Created
# on boot if absent; relative paths resolve against the hub's working
# directory.
HUB_DATA_DIR=.data/hub
# Directory of built user-interface files the hub serves at BASE_URL.
# Relative paths resolve against the hub's working directory (apps/hub
# under `bun run dev`), so ../web/dist is the web app's build output;
# produce it with `bun run build` before starting the hub. Any directory
# with an index.html works — ../hub/public is a minimal placeholder page.
HUB_STATIC_DIR=../web/dist
# The administrator account: `bun run dev` seeds it once the hub answers
# so a fresh checkout can sign in immediately, and `workbench setup` /
# `workbench seed` authenticate as it. Sign in with these credentials
# right away. In `bun run dev`, leave either value empty to skip seeding
# (hosted deployments do not run `bun run dev`). The hub itself also
# authenticates as this account (and resolves ORG_SLUG below) to find
# the operator bench for the env-key auto-plant — see ANTHROPIC_API_KEY
# further down.
# Administrator identity. Unset values fall back to the defaults shown —
# fine for local development, set both for real deployments.
# HUB_ADMIN_EMAIL=alice@example.com
# HUB_ADMIN_PASSWORD=password123
# The operator bench's slug — `workbench setup` creates it, `workbench
# seed` and the hub's own env-key auto-plant resolve it. Unset falls
# back to "workbench", the same default those commands use.
# ORG_SLUG=workbench
# Everything below is optional. Leave a variable unset to leave the
# feature it configures off; the hub never treats a partially-set group
# as configured — it fails loudly at boot instead.
# The tenant every self-served personal bench is parented under. Leave
# unset: the operator tenant it would parent under does not exist as
# real infrastructure yet, so self-served benches are unparented
# top-level tenants until it does.
# OPERATOR_TENANT_ID=
# Per-IP rate limit on email sign-up. Defaults to 5 sign-ups per 60
# seconds when unset.
# SIGNUP_RATE_LIMIT_WINDOW_SECONDS=60
# SIGNUP_RATE_LIMIT_MAX=5
# Per-account rate limit on email sign-in, keyed on the target email
# rather than client IP (client IP can't be trusted as a sign-in key in
# this deployment — see sign-in-rate-limit.ts). Defaults to 10 attempts
# per 60 seconds when unset — deliberately looser than better-auth's
# built-in 3-per-10-seconds default, which is tight enough that a mistyped
# password can lock an account out mid-window. See CL-6494.
# SIGNIN_RATE_LIMIT_WINDOW_SECONDS=60
# SIGNIN_RATE_LIMIT_MAX=10
# Self-serve signup mode. Hub default is closed (owner adds users or
# shares a copy-link invite). Local `bun run dev` opens signup when this
# is unset so the first admin can seed — set closed explicitly to test
# the closed gate. See docs/TENANCY.md.
# WORKBENCH_SIGNUP=open
# When WORKBENCH_SIGNUP=open, optionally restrict which email domains
# may register (comma-separated). Empty/unset = any domain.
# WORKBENCH_ALLOWED_EMAIL_DOMAINS=acme.example
# Your Anthropic API key — set it for real AI replies. The hub now
# plants it as a real, probed credential on the operator bench itself at
# hub start (the env-key auto-plant, CL-6101): no `workbench seed`
# re-run needed to make the catalog launchable. It also still decides
# whether a freshly self-served personal bench gets the default workflow
# set deployed at first login. `workbench seed` still reads it too, for
# CI/scripted use — both paths are idempotent against each other and
# against themselves; running either (or both, or a hub restart) any
# number of times plants the credential once.
# ANTHROPIC_API_KEY=
# Every other curated provider's key, read the same way and auto-planted
# the same way at hub start — set any subset of these, or none. See
# packages/onboarding/src/plant-env-credentials.ts (PROVIDER_ENV_VARS)
# for the full, authoritative list.
# OPENAI_API_KEY=
# GEMINI_API_KEY=
# XAI_API_KEY=
# OPENROUTER_API_KEY=
# OPENCODE_ZEN_API_KEY=
# GROQ_API_KEY=
# DEEPSEEK_API_KEY=
# MISTRAL_API_KEY=
# HUGGINGFACE_API_KEY=
# Set to 1 to make `workbench seed` also deploy the zero-cost
# catalog-test workflows (heartbeat, channel-digest), which exist only
# to exercise the platform's scheduling and channel-mail paths
# continuously. Leave unset for a real bench — these are dev/CI
# tooling, never part of a real user's workflow set.
# WORKBENCH_SEED_CATALOG_TEST_WORKFLOWS=
# Behind a reverse proxy (e.g. tailscale serve), BASE_URL is the public
# origin and PORT is the local port the proxy forwards to.
# PORT=3000
# OAuth sign-in. Each provider is an independent pair — set both values
# to turn its button on at the sign-in screen, leave both unset to
# leave it off. Setting only one half of a pair fails the hub at boot,
# naming the missing value, rather than silently disabling the
# provider. Email/password sign-in always stays available regardless.
#
# Google: create an OAuth client at
# https://console.cloud.google.com/apis/credentials, with an authorized
# redirect URI of <BASE_URL>/api/auth/callback/google.
# GOOGLE_CLIENT_ID=
# GOOGLE_CLIENT_SECRET=
#
# GitHub: create an OAuth app at
# https://github.com/settings/developers, with an authorization
# callback URL of <BASE_URL>/api/auth/callback/github.
# GITHUB_CLIENT_ID=
# GITHUB_CLIENT_SECRET=
# The `github` connector's hosted one-click connect (Plugins page and the
# in-room connect-github card) — a SEPARATE OAuth App from GITHUB_CLIENT_ID
# above, which only signs people in to Workbench itself. Create a second
# OAuth app at https://github.com/settings/developers, with an
# authorization callback URL of <BASE_URL>/api/tenants/ — GitHub matches
# any redirect under that prefix, and the flow's actual callback is the
# tenant-scoped <BASE_URL>/api/tenants/<tenant-id>/connections/oauth/github/callback
# (CL-6394). The connect asks for the "repo" scope. Leave both unset and
# Connect GitHub falls back to a guided personal-access-token paste — no
# dead end either way.
# GITHUB_APP_CLIENT_ID=
# GITHUB_APP_CLIENT_SECRET=
# Gmail connector (read, draft, send — sending always waits for approval):
# create an OAuth client at https://console.cloud.google.com/apis/credentials
# (a separate client from GOOGLE_CLIENT_ID's sign-in app) with the Gmail
# API enabled. Google requires EXACT-match redirect URIs, so register the
# tenant-scoped callback for each tenant that will connect:
# <BASE_URL>/api/tenants/<tenant-id>/connections/oauth/gmail/callback
# The connect asks for the gmail.modify scope with offline access (the
# refresh token). Google's app verification for gmail scopes takes weeks —
# start it early; unverified apps are capped at 100 test users. Leave both
# unset and the Gmail connect card renders as not configured.
# GMAIL_CLIENT_ID=
# GMAIL_CLIENT_SECRET=
# Onboarding's Hugging Face connect card (a public OAuth app — no
# secret): create one at https://huggingface.co/settings/applications/new
# with a redirect URI of <BASE_URL>/api/onboarding/oauth/huggingface/callback
# (first-login onboarding) — the settings/plugins Connect buttons ride
# the tenant-scoped <BASE_URL>/api/tenants/<tenant-id>/connections/oauth/huggingface/callback
# instead (CL-6394), so register that shape too if your HF app supports
# it — and scope "openid inference-api". See
# docs/onboarding-huggingface-connect.md for the full setup. Leave unset
# and Hugging Face stays available only as a paste-a-token provider card.
# HUGGINGFACE_OAUTH_CLIENT_ID=
# Optional firm-memory plane (@corbits/memory). Uses DATABASE_URL — the
# same URL as everything else — in its own `memory` schema. Recommended:
# run `bun run setup:memory` for a machine-specific recommendation (native
# Ollama, Docker, or a remote endpoint, whichever this checkout can
# actually use) instead of hand-picking the block below.
#
# Leave EMBED_BASE_URL unset to boot without memory: memory_search/
# memory_add/memory_list then answer with a plain "memory isn't set up on
# this server yet" note instead of an error, and the tool isn't even
# offered to Myra. This is the one honest-degradation case worth being
# explicit about: setting EMBED_BASE_URL later does NOT retroactively
# embed anything written while it was unset — migrations create the
# tables either way, but there is no automatic backfill, so rows added
# before embedding was configured stay invisible to memory_search forever
# unless something re-adds them.
#
# Managed OpenAI embeddings:
# EMBED_BASE_URL=https://api.openai.com/v1
# EMBED_MODEL=text-embedding-3-small
# EMBED_API_KEY=
#
# Local dev with no external embedding account: point at a local Ollama
# instance instead (`ollama pull nomic-embed-text`, then `ollama serve`,
# the default at http://localhost:11434). No EMBED_API_KEY needed.
# EMBED_BASE_URL=http://localhost:11434
# EMBED_MODEL=nomic-embed-text
# EMBED_API_STYLE=ollama
#
# Memory plane tuning, all optional — leave unset for the defaults below.
# Max Postgres connections the memory plane's own pool opens. Default 8.
# DB_POOL_MAX=8
# Postgres full-text-search config name (e.g. "english"). Package default
# applies when unset.
# FTS_LANGUAGE=
# Embedding endpoint's request shape: "openai" (default), "tei" (a Text
# Embeddings Inference server), or "ollama" (a local/self-hosted Ollama
# instance's /api/embed).
# EMBED_API_STYLE=openai
# Timeout in milliseconds for a single embedding request. Package default
# applies when unset.
# EMBED_TIMEOUT_MS=
#
# Optional reranking step on memory search results — leave both
# RERANK_BASE_URL and RERANK_MODEL unset to search without reranking (the
# hub refuses to boot if only one of the pair is set, since a half-wired
# reranker can never work). Once both are set, a reranker outage degrades
# search quietly rather than breaking it — that's by design, not a bug.
# There's no local install for a reranker; the supported shape is a Text
# Embeddings Inference server, most easily run in Docker:
# docker run -d -p 8081:80 \
# ghcr.io/huggingface/text-embeddings-inference:cpu-latest \
# --model-id BAAI/bge-reranker-base
# Reranker endpoint base URL.
# RERANK_BASE_URL=http://localhost:8081
# Reranker model name.
# RERANK_MODEL=BAAI/bge-reranker-base
# Reranker API key, if the endpoint requires one.
# RERANK_API_KEY=
# Max characters of a candidate document sent to the reranker per call.
# RERANK_MAX_DOC_CHARS=
# Timeout in milliseconds for a single rerank request.
# RERANK_TIMEOUT_MS=
# Optional Markdown-artifact-to-PDF rendering (@corbits/gotenberg-render)
# through an operator-configured Gotenberg server. Leave unset to keep the
# PDF-render capability off entirely — nothing errors at startup either
# way. Gotenberg has no good native story, so this is Docker (or a remote
# endpoint) the same as the reranker:
# docker run --rm -p 3000:3000 gotenberg/gotenberg:8
# GOTENBERG_URL=http://localhost:3000
# Encrypts secrets at rest through Interchange's CredentialCipher seam —
# webhook-trigger signing secrets, and the onboarding OAuth connect state
# (PKCE verifier) sealed between /start and /callback so it survives a hub
# restart in between. 64 hex characters (32 bytes, AES-256): openssl rand
# -hex 32. Required for any real deployment — the hub refuses to boot
# without it. Leave unset and instead set ALLOW_PLAINTEXT_SECRETS below
# for local dev/test.
# CREDENTIAL_ENCRYPTION_KEY=
# Dev/test-only opt-out of the CREDENTIAL_ENCRYPTION_KEY requirement above:
# set to boot without a key, storing those secrets unencrypted with a boot
# warning. Uncommented here so a fresh checkout's `bun run dev` keeps
# working out of the box. Safe to inherit as-is: the hub refuses to boot
# with this set unless BASE_URL is also a loopback address (localhost /
# 127.0.0.1 / ::1), so it can never take effect against a real deployment
# even if this file is copied verbatim.
ALLOW_PLAINTEXT_SECRETS=1
# Opt-out of @workbench/access-policy's email-verification requirement.
# The hub has no transactional email wired yet, so NO account can ever
# become verified — leaving this unset makes `bun run setup` and every
# self-signup provisioning fail with signup_not_allowed. It therefore
# ships ON for local development. Turn it off (and wire verification)
# before exposing a deployment where invite redemption must prove
# address ownership.
ALLOW_UNVERIFIED_EMAILS=1
# Artifacts plane (@corbits/artifacts) uses DATABASE_URL too — different
# schema only (`artifacts.*` FKs into public.tenant/principal). Nothing to
# configure here; `bun run dev` mounts Library automatically.
# Slack tag ingress (@corbits/slack-tag, docs/slack.md) — talk to a
# workbench agent from Slack. Leave SLACK_BOT_TOKEN/SLACK_SIGNING_SECRET
# unset to run with no Slack app mounted (the default); set both from your
# Slack app's "OAuth & Permissions" and "Basic Information" pages to turn
# it on. SLACK_WORKBENCH_TENANT_SLUG and SLACK_DEFAULT_AGENT_DEFINITION_ID
# are then also required — see docs/slack.md — since there is no honest
# default for which bench a Slack workspace's messages land in or which
# deployed agent answers them.
# SLACK_BOT_TOKEN=
# SLACK_SIGNING_SECRET=
# SLACK_WORKBENCH_TENANT_SLUG=
# SLACK_DEFAULT_AGENT_DEFINITION_ID=
# Exclusive per-workbench sidecar placement (CL-6096, CL-6283). Leave unset
# (the default) to keep every workbench on the hub's current single shared
# sidecar, with no exclusive-placement backend registered — a workbench's
# "run this workbench on its own sidecar" setting still saves, but exclusive
# deployments fail closed until a provisioner is configured here.
#
# SIDECAR_PROVISIONERS is a comma-separated list of backend ids to register,
# e.g. "docker" (each id has its own required settings below it — "docker"
# needs DOCKER_PROVISIONER_IMAGE). SIDECAR_DEFAULT_PROVISIONER picks which
# listed id exclusive placements provision on; optional when exactly one id
# is listed, required when listing more than one.
# SIDECAR_PROVISIONERS=docker
# SIDECAR_DEFAULT_PROVISIONER=docker
# DOCKER_PROVISIONER_IMAGE=
# HUB_SIDECAR_WEBSOCKET_URL overrides the ws(s):// address a provisioned
# sidecar dials back to reach this hub. Leave unset to derive it from
# BASE_URL — fine when the hub and its sidecars can reach each other at
# that address. Set this explicitly whenever SIDECAR_PROVISIONERS includes
# "docker": a docker sidecar container's own "localhost" is itself, not the
# hub host, so BASE_URL's derived ws:// URL cannot reach the hub from
# inside it.
# HUB_SIDECAR_WEBSOCKET_URL=
# SIDECAR_ADAPTER_MANIFEST configures custom Interchange inference adapters
# for a sidecar process, replacing the default manifest wholesale (not
# merging with it). Leave unset (the default) and the sidecar already
# registers @corbits/ollama-adapter for the "ollama" provider key, so a
# seeded Ollama model's per-model num_ctx reaches Ollama with no operator
# configuration. Set this only to point a provider key at a different
# adapter package. The value is a JSON array of
# {"provider","specifier","export"} entries; each specifier must resolve
# from the sidecar's own module-resolution root (an installed package, not
# a bare file path), and every workflow-process child it spawns resolves
# the same manifest. Example replacing the default with a custom adapter
# for the "anthropic" provider key:
# SIDECAR_ADAPTER_MANIFEST=[{"provider":"anthropic","specifier":"@acme/custom-anthropic-adapter","export":"createCustomAdapter"}]