Environment reference
Everything the app reads from its environment, in one place. Configuration that describes your site lives in docs.yaml; the environment carries what differs per deployment: paths, connection strings, and secrets. API keys in particular are environment-only and never belong in config.
Core
| Variable | Default | What it does |
|---|---|---|
READSMITH_CONTENT |
apps/web/content |
Directory holding your docs content (where docs.yaml lives) |
DATABASE_URL |
unset | Postgres connection string; without it the app runs docs-only (pages and agent outputs work, search and Ask AI stay off) |
PORT |
4321 |
Host port the compose file publishes the app on |
Storage
| Variable | Default | What it does |
|---|---|---|
STORAGE_DRIVER |
local |
Bundle store driver: local (filesystem) or s3 (any S3-compatible store) |
STORAGE_ROOT |
apps/web/.readsmith |
local driver: root of the bundle store, the compiled site artifact the app serves |
STORAGE_ENDPOINT |
unset | s3 driver: scheme + host, e.g. http://minio:9000 or your R2 account endpoint |
STORAGE_BUCKET |
unset | s3 driver: the bucket holding the bundle store |
STORAGE_ACCESS_KEY_ID |
unset | s3 driver: access key |
STORAGE_SECRET_ACCESS_KEY |
unset | s3 driver: secret key |
STORAGE_REGION |
auto |
s3 driver: SigV4 region (auto works for R2 and MinIO) |
READSMITH_STORAGE_ROOT |
unset | Filesystem root for persisted spec blobs (the database-backed API reference ingest); a mounted volume in compose |
The s3 driver speaks to Cloudflare R2, MinIO, or any S3-compatible store. For
a bundled MinIO, start compose with the opt-in profile: docker compose --profile s3 up brings up MinIO with a console on :9001 and creates the
bucket on first start. The default deployment needs none of this; the
filesystem driver remains the zero-config path.
Git deploys
The full setup lives in Deploy on push; this is the reference. Configure exactly one auth mode: the App pair or a PAT, never both.
| Variable | Default | What it does |
|---|---|---|
GITHUB_APP_ID |
unset | App mode: the GitHub App's id (pairs with the private key) |
GITHUB_APP_PRIVATE_KEY |
unset | App mode: the App's private key, \n-escaped on one line |
GITHUB_PAT |
unset | PAT mode: a fine-grained personal access token (read-only contents) |
GITHUB_WEBHOOK_SECRET |
unset | Verifies webhook deliveries; required for the webhook path |
GITHUB_REPO |
unset | The owner/name to serve; binding auto-builds a site with no history |
GITHUB_BRANCH |
repo default | Build a branch other than the repository's default |
GITHUB_POLL_INTERVAL |
off | Polling fallback, seconds, for instances webhooks cannot reach |
READSMITH_KEEP_DEPLOYMENTS |
20 |
Rollback history kept per site; older snapshots prune after each publish (0 disables) |
READSMITH_FAIL_ON_ERROR |
false |
Strict builds: any page error fails the deploy instead of publishing with diagnostics |
AI keys
Keys resolve in a fixed order: a role-specific override wins, then the provider-native variable for whichever provider your docs.yaml names.
| Variable | Role |
|---|---|
READSMITH_AI_CHAT_KEY |
Overrides the chat (Ask AI) key, whatever the provider |
READSMITH_AI_EMBEDDING_KEY |
Overrides the embedding (semantic search) key |
READSMITH_AI_RERANK_KEY |
Overrides the rerank key, when rerank is enabled |
OPENAI_API_KEY |
Native key when a model uses the openai provider |
ANTHROPIC_API_KEY |
Native key for the anthropic provider |
GOOGLE_GENERATIVE_AI_API_KEY |
Native key for the google provider |
AI_GATEWAY_API_KEY |
Native key for the gateway provider |
A missing embedding key degrades search to keyword-only; a missing chat key turns Ask AI off. Neither breaks the site.
Rate limits
Defaults protect a public deployment out of the box: Ask AI 10 requests per minute, search 60, MCP 60, per client IP. The environment overrides docs.yaml at deploy time.
| Variable | Format | What it does |
|---|---|---|
READSMITH_RATE_LIMIT |
true / false |
Master switch for the built-in limiter |
READSMITH_RATE_LIMIT_ASK |
10 or 10/30 |
Ask AI policy: a count per minute, or count per N seconds |
READSMITH_RATE_LIMIT_SEARCH |
same | Search policy |
READSMITH_RATE_LIMIT_MCP |
same | MCP policy |
READSMITH_TRUSTED_IP_HEADER |
header name | The proxy header to read the client IP from; unset, the socket address is used |
Content-Security-Policy
CSP sources from the environment add to docs.yaml security.csp and to the strict defaults. These are read at build time, not at start: set them before next build (the compose image build), not on a running container.
| Variable | Adds sources to |
|---|---|
READSMITH_CSP_IMG_SRC |
img-src |
READSMITH_CSP_CONNECT_SRC |
connect-src |
READSMITH_CSP_FONT_SRC |
font-src |
READSMITH_CSP_FRAME_SRC |
frame-src |
READSMITH_CSP_FRAME_ANCESTORS |
frame-ancestors |
Operations
| Variable | Default | What it does |
|---|---|---|
CACHE_DRIVER |
memory |
The query-embedding cache driver; in-memory suits a single instance |
READSMITH_LOG_LEVEL |
info |
Log verbosity |
READSMITH_WORKER_CONCURRENCY |
2 |
Background job concurrency |
READSMITH_SITE_CACHE_MAX |
16 |
Hydrated site bundles held in memory; single-site installs never need more than one |
READSMITH_MIGRATIONS_DIR |
resolved from the package | Where database migrations load from; the compose image sets it, you rarely will |
Compose-only
POSTGRES_USER, POSTGRES_PASSWORD, and POSTGRES_DB are consumed by the compose file to configure the database container and assemble DATABASE_URL. The app itself only ever reads DATABASE_URL.